【FFT(母函数)+容斥】BZOJ3771-Triple

【题目大意】

给出 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\n",i,num);
71     }
72 }
73 
74 int main()
75 {
76     init();
77     solve();
78     get_ans();
79     return 0;
80 }

 

posted @ 2016-07-29 11:01  iiyiyi  阅读(1416)  评论(0编辑  收藏  举报