BZOJ 3771 Triple (FFT+生成函数+容斥)
题目大意:给你互不相同的$n$个数,在其中任选$1$~$3$个数,不能重复选数,设它们的和为$S$。对于所有可能的$S$,求选出的数和为$S$方案总数,选数没有顺序。
先对所有的数弄一个生成函数$A$,有数的位置权值为$1$
如果我们要选$x$个数,求方案数。只需要对$A$求$x$次卷积。
然而题目要求选数是无序的,且不能重复选数
选$1$个数的方案就是$A$
选$2$个数时,需要去掉重复选同一个数的情况,即$(A*A-B)/2$,$B$是相同的数选$2$次时的生成函数
选$3$个数的情况更复杂
1.首先要去掉重复选$3$次同一个数的情况,设相同的数选$3$次时的生成函数为$C$
2.还要去掉 选$2$次相同的数,再选另一个数的情况,这种情况的生成函数是$3*B*A$
然而情况二还可能把情况一去掉,需要再加回来
最终答案就是$A+(A*A-B)/2+(A*A*A-3*B*A+2*C)/6$
1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define N1 (1<<18)+10 6 #define ll long long 7 #define dd double 8 using namespace std; 9 10 11 int gint() 12 { 13 int ret=0,fh=1; char c=getchar(); 14 while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();} 15 while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();} 16 return ret*fh; 17 } 18 19 int r[N1]; 20 const dd pi=acos(-1); 21 struct cp{ 22 dd x,y; 23 friend cp operator + (const cp &s1,const cp &s2){ return (cp){s1.x+s2.x,s1.y+s2.y}; } 24 friend cp operator - (const cp &s1,const cp &s2){ return (cp){s1.x-s2.x,s1.y-s2.y}; } 25 friend cp operator * (const cp &s1,const cp &s2){ return (cp){s1.x*s2.x-s1.y*s2.y,s1.y*s2.x+s1.x*s2.y}; } 26 }a[N1],b[N1],c[N1],f[N1]; 27 28 void init() 29 { 30 memset(a,0,sizeof(a)); 31 memset(b,0,sizeof(b)); 32 memset(c,0,sizeof(c)); 33 } 34 35 void FFT(cp *s,int len,int type) 36 { 37 int i,j,k; cp wn,w,t; 38 for(i=0;i<len;i++) if(i<r[i]) swap(s[i],s[r[i]]); 39 for(k=2;k<=len;k<<=1) 40 { 41 wn=(cp){cos(2.0*pi*type/k),sin(2.0*pi*type/k)}; 42 for(i=0;i<len;i+=k) 43 { 44 w=(cp){1,0}; 45 for(j=0;j<(k>>1);j++,w=w*wn) 46 { 47 t=w*s[i+j+(k>>1)]; 48 s[i+j+(k>>1)]=s[i+j]-t; 49 s[i+j]=s[i+j]+t; 50 } 51 } 52 } 53 } 54 int n,ma,len,L; 55 int v[N1],s1[N1],s2[N1],s3[N1],ans[N1]; 56 57 int main() 58 { 59 scanf("%d",&n); int i; 60 for(i=1;i<=n;i++) v[i]=gint(),ma=max(ma,v[i]),s1[v[i]]++; // 1 -> A 61 62 for(len=1,L=0;len<3*ma;len<<=1,L++); 63 for(i=1;i<=n;i++) a[v[i]].x=1,b[v[i]<<1].x=1;//c[v[i]*3].x=1; 64 for(i=0;i<len;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1)); 65 FFT(a,len,1); FFT(b,len,1);// FFT(c,len,1); 66 67 for(i=0;i<len;i++) f[i]=a[i]*a[i]; // 2 -> (A*A-B)/2 68 FFT(f,len,-1); 69 for(i=1;i<=n;i++) s2[v[i]<<1]--; 70 for(i=0;i<len;i++) s2[i]=(int)(f[i].x/len+0.1); 71 for(i=0;i<len;i++) s2[i]/=2; 72 73 for(i=0;i<len;i++) f[i]=a[i]*a[i]*a[i]; // 3 -> (A*A*A-3*B*A+2*C)/6 74 FFT(f,len,-1); 75 for(i=0;i<len;i++) s3[i]+=(int)(f[i].x/len+0.1); 76 for(i=0;i<len;i++) f[i]=a[i]*b[i]; 77 FFT(f,len,-1); 78 for(i=0;i<len;i++) s3[i]-=( (int)(f[i].x/len+0.1) )*3; 79 for(i=1;i<=n;i++) s3[v[i]*3]+=2; 80 for(i=0;i<len;i++) s3[i]/=6; 81 82 for(i=1;i<=len;i++) if(s1[i]+s2[i]+s3[i]>0) 83 printf("%d %d\n",i,s1[i]+s2[i]+s3[i]); 84 85 return 0; 86 }