【题目大意】
给出 n个物品,价值为别为Xi且各不相同,现在可以取1个、2个或3个,问每种价值和有几种情况?
*顺序不同算一种
【思路】
显然是个母函数,A表示每种物品取一个的情况,B表示每种物品取二个的情况,C表示每种物品取三个的情况。用指数表示价值,系数表示该价值的个数,显然多项式相乘后指数会相加,系数会相乘,很容易就求出来了。
所以对于每种物品价值Xi,A[xi]++,B[2*xi]++,C[3*xi]++。
如果取1个物品,答案就是A。
如果取2个物品,A^2中有重复的(xi,xi)的情况,所以答案为A^2-B。
如果去3个物品,A^3中可能有(xi,xi,xi)(xi,xi,yi)(xi,yi,xi)(yi,xi,xi)这几种重复的情况,而A*B能够求出所有形容(xi,xi,xi)和(xi,yi,yi)的情况数。(xi,xi,yi)(xi,yi,xi)(yi,xi,xi)总的情况数=(xi,yi,yi)*3,而A*B*3又会多减去了两次(xi,xi,xi),所以要用C加回来。所以答案为A^3-3*B*A+2C。又由于顺序不同算一种情况,因为每种物品价值都不一样,情况(2)/2,情况(3)/6。
故总情况数量=++
(公式好烦啊把默认编辑器换成Markdown算了)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<complex> 6 #include<cmath> 7 #define pi acos(-1) 8 using namespace std; 9 typedef complex<double> com; 10 typedef long long ll; 11 const int MAXN=262144+50; 12 com a[MAXN],b[MAXN],c[MAXN]; 13 int m,n,len,L,Rev[MAXN]; 14 void get_bit(){for (n=1,L=0;n<m;n<<=1) L++;} 15 void get_Rtable(){for (int i=0;i<n;i++) Rev[i]=(Rev[i>>1]>>1)|((i&1)<<(L-1));} 16 17 void FFT(com* a,int flag) 18 { 19 for (int i=0;i<n;i++)if(i<Rev[i])swap(a[i],a[Rev[i]]); //利用逆序表,快速求逆序 20 for (int i=1;i<n;i<<=1) 21 { 22 com wn(cos(2*pi/(i*2)),flag*sin(2*pi/(i*2))); 23 for (int j=0;j<n;j+=(i<<1)) 24 { 25 com w(1,0); 26 for (int k=0;k<i;k++,w*=wn) 27 { 28 com x=a[j+k],y=w*a[j+k+i]; 29 a[j+k]=x+y; 30 a[j+k+i]=x-y; 31 } 32 } 33 } 34 if (flag==-1) for (int i=0;i<n;i++) a[i]/=n; 35 } 36 37 38 void init() 39 { 40 scanf("%d",&n); 41 for (int i=0;i<n;i++) 42 { 43 int ai; 44 scanf("%d",&ai); 45 a[ai]+=(1);b[2*ai]+=(1);c[3*ai]+=(1); 46 len=max(len,3*ai); 47 } 48 } 49 50 void solve() 51 { 52 m=len<<1; 53 len++;m++; 54 get_bit(); 55 get_Rtable(); 56 FFT(a,1); 57 FFT(b,1); 58 FFT(c,1); 59 com t2=(2),t3=(3),t6=(6); 60 for (int i=0;i<n;i++) 61 a[i]=(a[i]*a[i]*a[i]-t3*a[i]*b[i]+t2*c[i])/t6+(a[i]*a[i]-b[i])/t2+a[i]; 62 FFT(a,-1); 63 } 64 65 void get_ans() 66 { 67 for (int i=1;i<m;i++) 68 { 69 ll num=(ll)(a[i].real()+0.5); 70 if (num!=0) printf("%d %d ",i,num); 71 } 72 } 73 74 int main() 75 { 76 init(); 77 solve(); 78 get_ans(); 79 return 0; 80 }