[BZOJ5302][HAOI2018]奇怪的背包(DP)
由裴蜀定理得,一个集合S能得到w当且仅当gcd(S+{P})|w。
于是f[i][j]表示前i个物品gcd为j的方案数,发现gcd一定是P的因数,故总复杂度$O(n\sqrt{P}\log P)$(需要二分或者map)。
又发现,将所有数a[i]全都变成gcd(a[i],P)对答案是没有影响的,于是物品数也变成了P的因子个数级别。
故总复杂度为P的因子个数的平方*log P。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 typedef long long ll; 5 using namespace std; 6 7 const int M=2010,mod=1e9+7; 8 int n,m,P,tot,x,d[M],cnt[M],f[M][M],ans[M]; 9 10 void inc(int &x,int y){ x+=y; if (x>=mod) x-=mod; } 11 int gcd(int a,int b){ return b ? gcd(b,a%b) : a; } 12 13 int main(){ 14 freopen("bzoj5302.in","r",stdin); 15 freopen("bzoj5302.out","w",stdout); 16 scanf("%d%d%d",&n,&m,&P); 17 for (int i=1; i*i<=P; i++) if (P%i==0){ 18 d[++tot]=i; cnt[tot]=1; 19 if (i*i!=P) d[++tot]=P/i,cnt[tot]=1; 20 } 21 sort(d+1,d+tot+1); f[0][0]=1; 22 rep(i,1,n){ 23 scanf("%d",&x); 24 int t=lower_bound(d+1,d+tot+1,gcd(P,x))-d; 25 cnt[t]=(cnt[t]<<1)%mod; 26 } 27 rep(i,1,tot) rep(j,0,tot){ 28 inc(f[i][j],f[i-1][j]); 29 int t=lower_bound(d+1,d+tot+1,gcd(d[i],d[j]))-d; 30 inc(f[i][t],1ll*f[i-1][j]*(cnt[i]-1)%mod); 31 } 32 rep(i,1,tot) rep(j,1,i) if (d[i]%d[j]==0) inc(ans[i],f[tot][j]); 33 rep(i,1,m) scanf("%d",&x),printf("%d\n",ans[lower_bound(d+1,d+tot+1,gcd(P,x))-d]); 34 return 0; 35 }