https://www.lydsy.com/JudgeOnline/problem.php?id=3771
大意:给n把不同价值的斧子,从中选一把/两把/三把,所构成的每种价值和的可能情况有多少。
生成函数,指数为价值,系数即为可能情况数。
但是直接FFT乘会有两把/三把斧子拿的同一个的情况。
于是我们多存两个数组,分别记录两把/三把同时拿一把的生成函数,之后就容斥一下就行啦!
(注意拿的顺序不同也算是同一种情况,不要忘记除下去)
#include<cstdio> #include<cctype> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> using namespace std; typedef long long ll; typedef long double dl; const dl pi=acos(-1.0); const int N=3e5+5; inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch=='-';ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } struct complex{//定义复数 dl x,y; complex(dl xx=0.0,dl yy=0.0){ x=xx;y=yy; } complex operator +(const complex &b)const{ return complex(x+b.x,y+b.y); } complex operator -(const complex &b)const{ return complex(x-b.x,y-b.y); } complex operator *(const complex &b)const{ return complex(x*b.x-y*b.y,x*b.y+y*b.x); } }; void FFT(complex a[],int n,int on){ for(int i=1,j=n>>1;i<n-1;i++){ if(i<j)swap(a[i],a[j]); int k=n>>1; while(j>=k){j-=k;k>>=1;} if(j<k)j+=k; } for(int i=2;i<=n;i<<=1){ complex res(cos(-on*2*pi/i),sin(-on*2*pi/i)); for(int j=0;j<n;j+=i){ complex w(1,0); for(int k=j;k<j+i/2;k++){ complex u=a[k],t=w*a[k+i/2]; a[k]=u+t; a[k+i/2]=u-t; w=w*res; } } } if(on==-1) for(int i=0;i<n;i++)a[i].x/=n; } int n,m; complex a[N],b[N],c[N],d[N]; int main(){ n=read(); for(int i=1;i<=n;i++){ int w=read();m=max(m,w); a[w].x=1; b[w*2].x=1; c[w*3].x=1; } m=m*3; int nn=1; while(nn<m)nn<<=1; FFT(a,nn,1);FFT(b,nn,1);FFT(c,nn,1); for(int i=0;i<nn;i++){ complex t1(1.0/2.0,0); complex t2(3.0,0); complex t3(2.0,0); complex t4(1.0/6.0,0); d[i]=d[i]+a[i]; d[i]=d[i]+(a[i]*a[i]-b[i])*t1; d[i]=d[i]+(a[i]*a[i]*a[i]-t2*a[i]*b[i]+t3*c[i])*t4; } FFT(d,nn,-1); for(int i=0;i<m;i++){ int w=d[i].x+0.5; if(w)printf("%d %d ",i,w); } return 0; }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/ +
+++++++++++++++++++++++++++++++++++++++++++