[BZOJ5302][DP][裴蜀定理]HAOI2018:奇怪的背包

版权声明:虽然博主很菜,但是还是请注明出处(我觉得应该没人偷我的博客) https://blog.csdn.net/qq_43346903/article/details/88012366

BZOJ5302

裴蜀定理: g c d ( a , b ) a x + b y gcd(a,b)|ax+by
所以对于 v [ i ] v[i] ,有 d g c d ( v [ i ] , p ) d d,gcd(v[i],p)|d 会产生贡献
对于 w [ i ] w[i] ,其实是查询 g c d ( w [ i ] , p ) gcd(w[i],p)
1e9 的约数最多1e3个
所以dp预处理, d p [ i ] [ j ] dp[i][j] 表示到第 i i 个物品,gcd为 j j 的方案数

Code:

#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define ll long long
#define mod 1000000007
using namespace std;
using namespace tr1;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
inline int add(int x,int y){x+=y;if(x>=mod) x-=mod;return x;}
unordered_map<int,int>f[2],ans,a;
unordered_map<int,int>::iterator x,y;
int n,m,p;
void dp(){
	int now=0,nxt=f[0][p]=1;
	int cnt=0;
	for(x=a.begin();x!=a.end();x++){
		f[nxt].clear(),++cnt;
		for(y=f[now].begin();y!=f[now].end();y++){
			f[nxt][y->first]=add(f[nxt][y->first],y->second);
			f[nxt][__gcd(y->first,x->first)]=add(f[nxt][__gcd(y->first,x->first)],add(x->second,mod-1)*(ll)y->second%mod);
		}
		now=nxt,nxt^=1;
	}
	for(int i=1;i*(ll)i<=p;i++) if(!(p%i)) ans[i]=ans[p/i]=0;
	for(x=ans.begin();x!=ans.end();x++)
		for(y=f[now].begin();y!=f[now].end();y++) if(!(x->first%y->first)) x->second=add(x->second,y->second);
}
int main(){
	n=read(),m=read(),p=read();
	for(int i=1;i<=n;i++){
		int gcdd=__gcd(read(),p);
		if(!a[gcdd]) a[gcdd]=2;
		else (a[gcdd]*=2)%=mod;
	}
	dp();
	while(m--) cout<<ans[__gcd(read(),p)]<<"\n";
}

猜你喜欢

转载自blog.csdn.net/qq_43346903/article/details/88012366