BZOJ5302 [HAOI2018]奇怪的背包 【数论 + dp】
题目
小 CC 非常擅长背包问题,他有一个奇怪的背包,这个背包有一个参数 PP ,当他 向这个背包内放入若干个物品后,背包的重量是物品总体积对 PP 取模后的结果. 现在小 CC 有 nn 种体积不同的物品,第 ii 种占用体积为 V_iV
i
,每种物品都有无限个. 他会进行 qq 次询问,每次询问给出重量 w_iw
i
,你需要回答有多少种放入物品的方 案,能将一个初始为空的背包的重量变为 w_iw
i
.注意,两种方案被认为是不同的, 当且仅当放入物品的种类不同,而与每种物品放入的个数无关.不难发现总的方 案数为 2^n2
n
. 由于答案可能很大,你只需要输出答案对1e9+7取模的结果.
输入格式
从文件 knapsack.inknapsack.in 中读入数据. 第一行三个整数 nn , qq , PP ,含义见问题描述. 接下来一行 nn 个整数表示 V_iV
i
. 接下来一行 qq 个整数表示 w_iw
i
.
输出格式
输出到文件 knapsack.outknapsack.out 中. 输出 qq 行,每行一个整数表示答案.
输入样例
3 3 6
1 3 4
5 2 3
输出样例
5
6
6
提示

题解
考虑数论中的\(ax + by\)这样线性组合的形式,其只能表示\(gcd(a,b)\)的倍数
\(ax \mod P\)可以写成\(ax - Py\),也是\(a\)与\(P\)的线性组合
所以一个物品只能表示\(gcd(V[i],P)\)的倍数
我们只需要求出所有\(P\)的约数的方案数,对于询问\(W[i]\),我们只需要查询\(gcd(W[i],P)\)的倍数的方案数
设\(f[i][j]\)表示前\(i\)个数凑出以约数\(j\)为线性组合中的最小值的方案数【即\(j\)对其倍数的贡献】,转移即可
\(10^9\)以内约数最大不超过\(10^3\)个
建议别用STL
#include<iostream>
#include<cstdio>
#include<cmath>
#include<map>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
#define MAP map<int,int>
#define res register
using namespace std;
const int maxn = 1000005,maxm = 100005,INF = 1000000000,md = 1e9 + 7;
inline int read(){
res int out = 0,flag = 1; res char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
inline void write(int x){if (x >= 10) write(x / 10); putchar(x % 10 + '0');}
MAP f[2],Ans,A;
MAP::iterator it,IT;
int n,m,P;
inline int add2(int x,int y){x += y; if (x >= md) x -= md; return x;}
inline void add(int& x,int y){x += y; if (x >= md) x -= md;}
inline int gcd(int a,int b){return b ? gcd(b,a % b) : a;}
void init(){
int tmp,p = 1; f[0][P] = 1;
for (IT = A.begin(); IT != A.end(); IT++,p ^= 1){
f[p].clear();
for (it = f[p ^ 1].begin(); it != f[p ^ 1].end(); it++){
add(f[p][it->first],it->second);
tmp = gcd(IT->first,it->first);
add(f[p][tmp],1ll * add2(IT->second,md - 1) * it->second % md);
}
}
p ^= 1;
for (res int i = 1; 1ll * i * i <= P; i++) Ans[i] = Ans[P / i] = 0;
for (it = Ans.begin(); it != Ans.end(); it++)
for (IT = f[p].begin(); IT != f[p].end(); IT++)
if (it->first % IT->first == 0)
add(it->second,IT->second);
}
void solve(){
while (m--) write(Ans[gcd(read(),P)]),puts("");
}
int main(){
n = read(); m = read(); P = read();
int x;
for (res int i = 1; i <= n; i++){
x = gcd(read(),P);
if (!A.count(x)) A[x] = 2;
else A[x] = A[x] * 2 % md;
}
init();
solve();
return 0;
}
BZOJ5302 [HAOI2018]奇怪的背包 【数论 + dp】的更多相关文章
- BZOJ5302: [Haoi2018]奇怪的背包
BZOJ5302: [Haoi2018]奇怪的背包 https://lydsy.com/JudgeOnline/problem.php?id=5302 分析: 方程\(\sum\limits_{i=1 ...
- [HAOI2018]奇怪的背包 (DP,数论)
[HAOI2018]奇怪的背包 \(solution:\) 首先,这一道题目的描述很像完全背包,但它所说的背包总重量是在模P意义下的,所以肯定会用到数论.我们先分析一下,每一个物品可以放无数次,可以达 ...
- [BZOJ5302][HAOI2018]奇怪的背包(DP)
由裴蜀定理得,一个集合S能得到w当且仅当gcd(S+{P})|w. 于是f[i][j]表示前i个物品gcd为j的方案数,发现gcd一定是P的因数,故总复杂度$O(n\sqrt{P}\log P)$(需 ...
- BZOJ5302 HAOI2018奇怪的背包(动态规划)
由裴蜀定理,子集S有解当且仅当gcd(S,P)|w. 一个显然的dp是设f[i][j]为前i个数gcd为j的选取方案.注意到这里的gcd一定是P的约数,所以状态数是n√P的.然后可以通过这个得到gcd ...
- 【BZOJ5302】[HAOI2018]奇怪的背包(动态规划,容斥原理)
[BZOJ5302][HAOI2018]奇怪的背包(动态规划,容斥原理) 题面 BZOJ 洛谷 题解 为啥泥萌做法和我都不一样啊 一个重量为\(V_i\)的物品,可以放出所有\(gcd(V_i,P)\ ...
- 洛谷 P4495 [HAOI2018]奇怪的背包 解题报告
P4495 [HAOI2018]奇怪的背包 题目描述 小\(C\)非常擅长背包问题,他有一个奇怪的背包,这个背包有一个参数\(P\),当他 向这个背包内放入若干个物品后,背包的重量是物品总体积对\(P ...
- 洛谷P4495 [HAOI2018]奇怪的背包(数论)
题面 传送门 题解 好神仙的思路啊--orzyyb 因为不限次数,所以一个体积为\(V_i\)的物品可以表示出所有重量为\(\gcd(V_i,P)\)的倍数的物品,而所有物品的总和就是这些所有的\(\ ...
- haoi2018奇怪的背包题解
题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=5302 对于一个物品,设它体积为v,那么,在背包参数为p的情况下,它能达到gcd(v,p ...
- [HAOI2018]奇怪的背包
题目 暴力\(dp\)好有道理啊 于是我们来个反演吧 考虑一个体积序列\(\{v_1,v_2,...v_n\}\)能凑成\(w\)的条件 显然是 \[v_1x_1+v_2x_2+...+v_nx_n\ ...
随机推荐
- 题解 P4613 【[COCI2017-2018#5] Olivander】
话说这道题,作为一个哈迷,是不能错过的 我很惊讶本蒟蒻竟然看得懂题面 好了,闲话少说,这道题,虽说是入门难度,但凭着良心说,它还是一道普及 - 的吧 看到标签,“高性能”,大脑的第一反应是快读. 是不 ...
- 一些常用的集合工具的代码块(缓慢更新XD,更新了多属性过滤:) )
更新记录 虽然经常放鸽子,但是还是要记录一下更新 2017.8.30 更新了listToMap的方法,现在可以指定多个属性进行分组了,例如你要指定一个学生集合,按照名字和年龄相同的放在一组,现在只要调 ...
- swl字符串
创建字符串方法 去掉时间戳 #define NSLog(FORMAT, ...) printf("%s\n", [[NSString stringWithFormat:FORMAT ...
- 自己写一个Promise
参考Promise 的 官方规范 https://promisesaplus.com/ Promise 其实就是一个状态机 它只有两种状态变化 pending => fulfill ...
- VS Code 用户自定义代码片段(React)
VS Code 用户自定义代码片段(React) .jsxReact组件模板:javascriptreact.json { "Import React": { "pref ...
- caller、callee的用法及区别
1 :caller 返回一个调用当前函数的引用 如果是由顶层调用的话 则返回null (举个栗子哈 caller给你打电话的人 谁给你打电话了 谁调用了你 很显然是下面a函数的执行 只有在打电话的时 ...
- Django 模型与 Mysql 数据类型对应
Django 1.11.9 文件路径:site-packages\django\db\backends\mysql\base.py–class DatabaseWrapper _data_types ...
- JZ2440开发板与ubuntu互ping,然后进行文件的共享和挂载
操作手册如下:但本人直接用网线直接连通开发板的网口与电脑的网口没有成功过.采用路由器可以直接ping通,具体操作如下: 首先用网线将开发板和路由器连接.电脑无论是用wifi还是网线均可.然后关闭Win ...
- php下关于Cannot use a scalar value as an array的解决办法
今天在测试php程序的时候,出现了一个错误提示:Cannot use a scalar value as an array,这个错误提示前几天也出过,当时好像稍微调了一下就好了,也没深究,今天却又出现 ...
- 利用Django提供的ModelForm增删改数据
上一篇我们写了Django基于类如何增删改数据的方法,方法虽然简单,但新手可能对其原理不是很清楚,那么我们这次就用Django提供的ModelForm方法来实现增删改数据,这是一种基于现有模型的增删改 ...