[CC-ANUCBC]Cards, bags and coins
阿新 • • 發佈:2018-08-07
直接 std ins amp spa n-1 時間復雜度 動態 const 。
[CC-ANUCBC]Cards, bags and coins
題目大意:
給你\(n(n\le10^5)\)個數,\(q(q\le30)\)次詢問,問從中選取若幹個數使得這些數之和為\(m(m\le100)\)的方案數。
思路:
不難想到一個比較暴力的動態規劃,用\(f[i][j]\)表示用了前\(i\)個數,和為\(j\)的方案數。時間復雜度\(\mathcal O(nmq)\)。
發現動態規劃中我們只關心每個數在模\(m\)意義下的值,因此直接用\(n\)個數轉移實在是太愚蠢了。
將這些數模\(m\)意義下相等的歸為一類,最多有\(m\)類。直接用這\(m\)類數轉移即可。
時間復雜度\(\mathcal O(qm^3)\)
源代碼:
#include<cstdio> #include<cctype> #include<algorithm> inline int getint() { register char ch; register bool neg=false; while(!isdigit(ch=getchar())) neg|=ch=='-'; register int x=ch^'0'; while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); return neg?-x:x; } typedef long long int64; const int N=2e5+1,mod=1e9+9,M=100; int a[N],f[M],g[M],fac[N],ifac[N],cnt[M],c[M]; void exgcd(const int &a,const int &b,int &x,int &y) { if(!b) { x=1,y=0; return; } exgcd(b,a%b,y,x); y-=a/b*x; } inline int inv(const int &x) { int ret,tmp; exgcd(x,mod,ret,tmp); return (ret%mod+mod)%mod; } inline int C(const int &n,const int &m) { return (int64)fac[n]*ifac[m]%mod*ifac[n-m]%mod; } int main() { for(register int i=fac[0]=1;i<N;i++) { fac[i]=(int64)fac[i-1]*i%mod; } ifac[N-1]=inv(fac[N-1]); for(register int i=N-1;i>=1;i--) { ifac[i-1]=(int64)ifac[i]*i%mod; } for(register int T=getint();T;T--) { const int n=getint(),q=getint(); for(register int i=1;i<=n;i++) a[i]=getint(); for(register int i=0;i<q;i++) { const int m=getint(); std::fill(&cnt[0],&cnt[m],0); for(register int i=1;i<=n;i++) { cnt[(a[i]%m+m)%m]++; } f[0]=1; std::fill(&f[1],&f[m],0); for(register int i=0;i<m;i++) { std::fill(&c[0],&c[m],0); for(register int j=0;j<=cnt[i];j++) { (c[(int64)i*j%m]+=C(cnt[i],j))%=mod; } std::copy(&f[0],&f[m],g); std::fill(&f[0],&f[m],0); for(register int j=0;j<m;j++) { for(register int k=0;k<m;k++) { (f[(j+k)%m]+=(int64)g[k]*c[j]%mod)%=mod; } } } printf("%d\n",f[0]); } } return 0; }
[CC-ANUCBC]Cards, bags and coins