1. 程式人生 > >BZOJ3771 Triple(FFT+容斥原理)

BZOJ3771 Triple(FFT+容斥原理)

ble algo pan double == max [] urn cstring

  思路比較直觀。設A(x)=Σxai。先把只選一種的統計進去。然後考慮選兩種,這個直接A(x)自己卷起來就好了,要去掉選同一種的情況然後除以2。現在得到了選兩種的每種權值的方案數,再把這個卷上A(x)。得到這個後考慮去重,其中重復的就是選了兩個相同的和另外一個,那麽再把選兩個相同的生成函數搞出來卷上A,減掉選三個相同的。把這個東西減掉之後再除以3。說了半天也不知道在說啥,總之是容斥原理很基礎的應用。

  有些卡精度,用long double才過,可能是我寫醜了。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include
<cstdlib> #include<cstring> #include<algorithm> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<0||c>9) {if (c==-) f=-1;c=getchar();} while (c>=0&&c<=9) x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; }
#define N 270000 #define double long double const double PI=3.14159265358979324; struct complex { double x,y; complex operator +(const complex&a) const { return (complex){x+a.x,y+a.y}; } complex operator -(const complex&a) const { return (complex){x-a.x,y-a.y}; } complex
operator *(const complex&a) const { return (complex){x*a.x-y*a.y,x*a.y+y*a.x}; } }w[N],v[N],u[N]; int n,m,t,a[N],r[N]; long long f[N]; void DFT(int n,complex *a,int p) { for (int i=0;i<n;i++) if (i<r[i]) swap(a[i],a[r[i]]); for (int i=2;i<=n;i<<=1) { complex wn=(complex){cos(2*PI/i),p*sin(2*PI/i)}; for (int j=0;j<n;j+=i) { complex w=(complex){1,0}; for (int k=j;k<j+(i>>1);k++,w=w*wn) { complex x=a[k],y=w*a[k+(i>>1)]; a[k]=x+y,a[k+(i>>1)]=x-y; } } } } void mul(int n,complex *a,complex *b) { for (int i=0;i<n;i++) r[i]=(r[i>>1]>>1)|(i&1)*(n>>1); for (int i=0;i<n;i++) a[i].y=a[i].x-b[i].x,a[i].x=a[i].x+b[i].x; DFT(n,a,1); for (int i=0;i<n;i++) a[i]=a[i]*a[i]; DFT(n,a,-1); for (int i=0;i<n;i++) a[i].x=a[i].x/n/4; } int main() { #ifndef ONLINE_JUDGE freopen("bzoj3771.in","r",stdin); freopen("bzoj3771.out","w",stdout); const char LL[]="%d %I64d\n"; #else const char LL[]="%d %lld\n"; #endif n=read(); for (int i=1;i<=n;i++) { int x=read(); m=max(m,x); w[x].x=v[x].x=f[x]=a[x]=1; } t=1;while (t<=(m<<1)) t<<=1; mul(t,w,v); for (int i=0;i<=m;i++) if (a[i]) w[i<<1].x--; for (int i=0;i<=m*2;i++) f[i]+=w[i].x=(int)(w[i].x/2+0.5); for (int i=m*2+1;i<t;i++) w[i].x=w[i].y=0; for (int i=0;i<=m;i++) v[i].x=a[i],v[i].y=0; for (int i=m+1;i<t;i++) v[i].x=v[i].y=0; t=1;while (t<=m*3) t<<=1; mul(t,w,v); for (int i=0;i<t;i++) u[i].x=(i&1)?0:a[i>>1]; for (int i=0;i<=m;i++) v[i].x=a[i],v[i].y=0; for (int i=m+1;i<t;i++) v[i].x=0,v[i].y=0; mul(t,u,v); for (int i=0;i<=m;i++) if (a[i]) u[i*3].x--; for (int i=0;i<=m*3;i++) f[i]+=(long long)((w[i].x-u[i].x)/3+0.5); for (int i=0;i<=m*3;i++) if (f[i]) printf(LL,i,f[i]); return 0; }

BZOJ3771 Triple(FFT+容斥原理)