spoj-TSUM Triple Sums
题解:
很吊的容斥+$FFT$,但是并不难。
首先,由于有重复,我们要容斥。
怎么办?
记录三个多项式,
只取一个:$w1$;
相同物体拿两个:$w2$;
相同物体拿三个:$w3$;
然后答案能推出来是$(w1*w1*w1-3*w1*w2+2*w3)/6$;
然后$FFT$瞎搞就行了。
注意有负数,同时扩大再瞎搞。
代码:
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 300000 #define ll long long const double Pi = acos(-1.0); template<typename T> inline void read(T&x) { T f=1,c=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();} x = f*c; } struct cp { double x,y; cp(){} cp(double x,double y):x(x),y(y){} cp operator + (const cp &a)const{return cp(x+a.x,y+a.y);} cp operator - (const cp &a)const{return cp(x-a.x,y-a.y);} cp operator * (const cp &a)const{return cp(x*a.x-y*a.y,x*a.y+y*a.x);} }; int to[N]; void fft(cp *a,int len,int k) { for(int i=0;i<len;i++) if(i<to[i])swap(a[i],a[to[i]]); for(int i=1;i<len;i<<=1) { cp w0(cos(Pi/i),k*sin(Pi/i)); for(int j=0;j<len;j+=(i<<1)) { cp w(1,0); for(int o=0;o<i;o++,w=w*w0) { cp w1 = a[j+o],w2 = w*a[j+o+i]; a[j+o] = w1+w2; a[j+o+i] = w1-w2; } } } if(k==-1) for(int i=0;i<len;i++) a[i].x=(ll)round(a[i].x/len+0.1); } int n,a[N],lim=1,l; cp w1[N],w2[N],w3[N],w4[N],w5[N]; int main() { // freopen("tt.in","r",stdin); read(n); for(int i=1;i<=n;i++) { read(a[i]); a[i]+=20000; } while(lim<240000)lim<<=1,l++; for(int i=1;i<lim;i++)to[i]=((to[i>>1]>>1)|((i&1)<<(l-1))); for(int i=1;i<=n;i++) { w1[a[i]].x++; w2[a[i]*2].x++; w3[a[i]*3].x++; } fft(w1,lim,1),fft(w2,lim,1); for(int i=0;i<lim;i++) { w4[i] = w1[i]*w1[i]*w1[i]; w5[i] = w1[i]*w2[i]; } fft(w4,lim,-1),fft(w5,lim,-1); for(int i=0;i<=120000;i++) { ll tmp = (ll)(w4[i].x-3*w5[i].x+2*w3[i].x+0.1)/6; if(tmp) printf("%d : %lld\n",i-60000,tmp); } return 0; }