BZOJ3771
题目描述
给出
n
n
n个物品,价值为别为
X
i
Xi
Xi且各不相同,现在可以取
1
1
1个、
2
2
2个或
3
3
3个,问每种价值和有几种情况?
顺序不同算一种
题解
定义
A
(
x
)
,
B
(
x
)
,
C
(
x
)
A(x),B(x),C(x)
A(x),B(x),C(x)分别表示每种物品取1个,2个,3个的生成函数。
那么分三种情况计算答案。
1,取1个物品
A
n
s
=
A
(
x
)
Ans=A(x)
Ans=A(x)
2,取2个物品
A
n
s
=
A
(
x
)
2
−
B
(
x
)
2
Ans=\frac{A(x)^2-B(x)}{2}
Ans=2A(x)2−B(x)
3,取3个物品
A
n
s
=
A
(
x
)
3
−
3
A
(
x
)
B
(
x
)
+
2
C
(
x
)
6
Ans=\frac{A(x)^3-3A(x)B(x)+2C(x)}{6}
Ans=6A(x)3−3A(x)B(x)+2C(x)
代码
#include <cmath>
#include <cstdio>
#include <climits>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
const int M=4e5+9;
const double pi=acos(-1.0);
int n,m,r[M],l,lim=1;
struct complex{
double x,y;
complex(double xx=0,double yy=0){x=xx,y=yy;}
friend inline complex operator+(complex a,complex b){return complex(a.x+b.x,a.y+b.y);}
friend inline complex operator-(complex a,complex b){return complex(a.x-b.x,a.y-b.y);}
friend inline complex operator*(complex a,complex b){return complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
friend inline complex operator/(complex a,double b){return complex(a.x/b,a.y/b);}
friend inline complex operator*(complex a,double b){return complex(a.x*b,a.y*b);}
}a[M],b[M],c[M],ans[M];
void FFT(complex *A,int type){
for(int i=0;i<lim;i++) if(i<r[i]) swap(A[i],A[r[i]]);
for(int mid=1;mid<lim;mid<<=1){
complex W(cos(pi/mid),type*sin(pi/mid));
for(int R=mid<<1,j=0;j<lim;j+=R){
complex w(1,0);
for(int k=0;k<mid;k++,w=w*W){
complex x=A[j+k],y=w*A[j+k+mid];
A[j+k]=x+y;
A[j+mid+k]=x-y;
}
}
}if(type==-1) for(int i=0;i<lim;i++) A[i]=A[i]/lim;
}
signed main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
int x;scanf("%d",&x);
a[x].x++,b[x*2].x++,c[x*3].x++;
m=max(m,x*3);
}
while(lim<m*2) lim<<=1,l++;
for(int i=0;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
FFT(a,1),FFT(b,1),FFT(c,1);
for(int i=0;i<=lim;i++) ans[i]=(a[i]*a[i]*a[i]-3.0*a[i]*b[i]+2.0*c[i])/6.0+(a[i]*a[i]-b[i])/2.0+a[i];
FFT(ans,-1);
for(int i=0;i<=m;i++)
if((int)(ans[i].x+0.5)) printf("%d %d\n",i,(int)(ans[i].x+0.5));
return 0;
}