(FFT)A+B Problem

 题目链接:https://cn.vjudge.net/contest/280041#problem/B

题目大意:给你n个数,然后让你找满足a[i] + a[j] = a[k] 的情况总数。

具体思路:首先把每一种情况的个数算出来(两个数相加的结果),然后再就是去重的过程。

(因为题目中会有负数,我们可以全部转换成非负数去进行计算)

1,自己和自己相加。

2,1+0=1,0+1=1这个时候,1是使用了两次,所以需要去掉这种情况,就是去掉(0的总数)*2.

3,0+0=0,0+0=0,这个时候我们可以按照第一种的思路来(这个时候i!=j,因为自己加自己情况已经去掉了),把其中一个0看成(非0的数),然后再按照公式进行计算,不过计算的时候是(0的总数-1)*2.

AC代码:

  1 #include<iostream>
  2 #include<cstring>
  3 #include<string>
  4 #include<cmath>
  5 #include<algorithm>
  6 #include<stdio.h>
  7 using namespace std;
  8 # define ll long long
  9 const double PI = acos(-1.0);
 10 const int maxn = 2e5+100;
 11 struct complex
 12 {
 13     double r,i;
 14     complex(double _r = 0,double _i = 0)
 15     {
 16         r = _r;
 17         i = _i;
 18     }
 19     complex operator +(const complex &b)
 20     {
 21         return complex(r+b.r,i+b.i);
 22     }
 23     complex operator -(const complex &b)
 24     {
 25         return complex(r-b.r,i-b.i);
 26     }
 27     complex operator *(const complex &b)
 28     {
 29         return complex(r*b.r-i*b.i,r*b.i+i*b.r);
 30     }
 31 };
 32 void change(complex y[],int len)
 33 {
 34     int i,j,k;
 35     for(i = 1, j = len/2; i < len-1; i++)
 36     {
 37         if(i < j)
 38             swap(y[i],y[j]);
 39         k = len/2;
 40         while( j >= k)
 41         {
 42             j -= k;
 43             k /= 2;
 44         }
 45         if(j < k)
 46             j += k;
 47     }
 48 }
 49 void fft(complex y[],int len,int on)
 50 {
 51     change(y,len);
 52     for(int h = 2; h <= len; h <<= 1)
 53     {
 54         complex wn(cos(-on*2*PI/h),sin(-on*2*PI/h));
 55         for(int j = 0; j < len; j += h)
 56         {
 57             complex w(1,0);
 58             for(int k = j; k < j+h/2; k++)
 59             {
 60                 complex u = y[k];
 61                 complex t = w*y[k+h/2];
 62                 y[k] = u+t;
 63                 y[k+h/2] = u-t;
 64                 w = w*wn;
 65             }
 66         }
 67     }
 68     if(on == -1)
 69         for(int i = 0; i < len; i++)
 70             y[i].r /= len;
 71 }
 72 const int T=5e4;
 73 complex x1[maxn<<1];
 74 ll num[maxn<<1],a[maxn<<1],b[maxn<<1];
 75 int main()
 76 {
 77     int n;
 78     scanf("%d",&n);
 79     int ans=0;
 80     int len=1;
 81     while(len<maxn)
 82         len<<=1;
 83     for(int i=0; i<n; i++)
 84     {
 85         scanf("%lld",&a[i]);
 86         if(a[i]==0)
 87             ans++;
 88         b[a[i]+T]++;
 89     }
 90     for(int i=0; i<len; i++)
 91     {
 92         x1[i]=complex(b[i],0);
 93     }
 94     fft(x1,len,1);
 95     for(int i=0; i<len; i++)
 96     {
 97         x1[i]=x1[i]*x1[i];
 98     }
 99     fft(x1,len,-1);
100     for(int i=0; i<len; i++)
101     {
102         num[i]=(ll)(x1[i].r+0.5);
103     }
104     for(int i=0; i<n; i++)
105     {
106         num[(a[i]+T)*2]--;
107     }//重复的去掉
108     ll sum=0;
109  //   cout<<num[T+T]<<endl;
110     for(int i=0; i<n; i++)
111     {
112         sum+=num[a[i]+2*T];//比如说 1 2 3 ,我们现在要计算能组成3的个数,也就是3加上 2 个T,因为他的两个因子分别有一个T
113         sum-=(ans-(a[i]==0))*2;// 0+4 =4 ,4+0=4,这个时候4是用了两遍的,所以减去的就应该是ans*2。
114        // 对于0+0等于0,这种情况,如果说当前只有两个0的话,num[0]是等于2的(去重之后),这个时候我们就把其中一个0看成非0的,然后再按照上面的步骤进行计算。
115     }
116     printf("%lld
",sum);
117     return 0;
118 }
原文地址:https://www.cnblogs.com/letlifestop/p/10302709.html