题目链接: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 }