2019.02.28【HAOI2018】【BZOJ5302】【洛谷P4495】奇怪的背包(裴蜀定理)
作者:互联网
BZOJ传送门
洛谷传送门
解析:
熟悉exgcd的人都知道这道题的结论。。。
每一个vi等价于gcd(vi,P)
最后要求的w在模意义下实际上就是gcd(w,P)
用O(P)时间处理出所有P的约数就能愉快地水过了 。
当然还是讲一下怎么做。
以下的vi和w均是取了gcd之后的。
由裴蜀定理,最后选择的vi要能够凑出w,需要满足i=1gcdt(vi)∣w。
所以只需要预处理出最终gcd等于每个约数的方案数就行了。
同时统计一下每个约数的因数前缀和
预处理复杂度大概是O(σ(P)2)=O(P32)
然后就可以O(1)回答每个询问了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<20|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re char c;
while(!isdigit(c=gc()));re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
struct Map{
cs static int magic=189859;
int key[magic],val[magic];
Map(){memset(key,-1,sizeof key);};
cs int &operator[](cs int &k)cs{
int h=k%magic;
while((~key[h])&&(key[h]^k))h=(h+1)%magic;
return val[h];
}
int &operator[](cs int &k){
int h=k%magic;
while((~key[h])&&(key[h]^k))h=(h+1)%magic;
if(key[h]^k)key[h]=k;
return val[h];
}
}id;
cs int mod=1e9+7;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(int a,int b){return a<b?a-b+mod:a-b;}
inline int mul(int a,int b){return (ll)a*b%mod;}
cs int N=1e6+6,M=1e5+5;
int n,q,P;
int v[N];
int factor[M],fcnt,cnt[M];
int f[M],now;
int ans[M];
int pow2[N],sum[N];
inline void sieve(){
for(int re i=1;(ll)i*i<=P;++i)if(P%i==0)factor[id[i]=++fcnt]=i;
for(int re i=fcnt;i;--i)if(P/factor[i]!=factor[i])factor[id[P/factor[i]]=++fcnt]=P/factor[i];
}
inline int gcd(int a,int b){
if(!a||!b)return a|b;
re int shift=__builtin_ctz(a|b);
for(b>>=__builtin_ctz(b);a;a-=b)if((a>>=__builtin_ctz(a))<b)swap(a,b);
return b<<shift;
}
inline void init(){
for(int re i=1;i<=n;++i)++cnt[id[gcd(v[i],P)]];
pow2[0]=1;
for(int re i=1;i<=n;++i)pow2[i]=mul(2,pow2[i-1]);
for(int re i=1;i<=n;++i)pow2[i]=dec(pow2[i],1);
for(int re i=1;i<=fcnt;++i)if(cnt[i]){
for(int re j=1;j<=fcnt;++j)if(f[j]){
int nxt=gcd(factor[i],factor[j]);
int pos=id[nxt];
f[pos]=add(f[pos],mul(f[j],pow2[cnt[i]]));
}
f[i]=add(f[i],pow2[cnt[i]]);
}
for(int re i=fcnt;i;--i)
for(int re j=i-1;j;--j)if(factor[i]%factor[j]==0)f[i]=add(f[i],f[j]);
}
signed main(){
n=getint();q=getint();P=getint();
sieve();
for(int re i=1;i<=n;++i)v[i]=getint();
init();
while(q--)cout<<f[id[gcd(getint(),P)]]<<"\n";
return 0;
}
标签:约数,www,P4495,洛谷,gcd,int,vi,2019.02,define 来源: https://blog.csdn.net/zxyoi_dreamer/article/details/88045837