# bzoj3771 Triple

FFT其实只是一个多项式点值表达式和系数表达式之间转换的一个工具，我们要做的就是理清楚各个多项式之间准确的关系，或者把卷积转化成原始的for循环理解

 1 #include <cstdio>
2 #include <cstring>
3 #include <iostream>
4 #include <algorithm>
5 #include <cmath>
6 #define MAXN 133333
7 using namespace std;
8 const double pi=acos(-1.0);
9 struct cmx{
10     double x,y;
11     cmx(){}
12     cmx(double a,double b){x=a,y=b;}
13     cmx operator + (cmx a){return cmx(x+a.x,y+a.y);}
14     cmx operator - (cmx a){return cmx(x-a.x,y-a.y);}
15     cmx operator * (cmx a){return cmx(x*a.x-y*a.y,x*a.y+y*a.x);}
16     cmx operator / (double a){return cmx(x/a,y/a);}
17     cmx operator * (double a){return cmx(x*a,y*a);}
18 }A[MAXN],B[MAXN],C[MAXN],ans[MAXN];
19 int n,N,rev[MAXN],maxn;
20 void fft(cmx *a,int o){
21     cmx dan,now,t;
22     register int i,j,k;
23     for(i=0;i<N;i++)if(i<rev[i])swap(a[i],a[rev[i]]);
24     for(k=2;k<=N;k<<=1){
25         dan=cmx(cos(2*pi/k),o*sin(2*pi/k));
26         for(j=0;j<N;j+=k){
27             now=cmx(1,0);
28             for(i=0;i<(k>>1);i++,now=now*dan){
29                 t=now*a[i+j+(k>>1)];
30                 a[i+j+(k>>1)]=a[i+j]-t;
31                 a[i+j]=a[i+j]+t;
32             }
33         }
34     }
35     if(o==-1)for(i=0;i<N;i++)a[i].x/=N;
36 }
37 int main(){
38     scanf("%d",&n);
39     register int i;
40     register long long now;
41     for(int i=1,x;i<=n;i++){
42         scanf("%d",&x);
43         A[x].x+=1;
44         B[x*2].x+=1;
45         C[x*3].x+=1;
46         maxn=max(maxn,3*x);
47     }
48     for(N=1;N<maxn;N<<=1);
49     for(i=0;i<N;i++){
50         if(i&1)rev[i]=(rev[i>>1]>>1)|(N>>1);
51         else rev[i]=rev[i>>1]>>1;
52     }
53     fft(A,1);fft(B,1);fft(C,1);
54     for(i=0;i<N;i++)
55         ans[i]=A[i]+(A[i]*A[i]-B[i])/2+(A[i]*A[i]*A[i]-A[i]*B[i]*3+C[i]*2)/6;
56     fft(ans,-1);
57     for(i=0;i<maxn;i++){
58         now=1ll*round(ans[i].x);
59         if(now>0)printf("%d %lld\n",i,now);
60     }
61     return 0;
62 }
View Code

posted @ 2018-02-26 20:52  Ren_Ivan  阅读(121)  评论(0编辑  收藏  举报