[BZOJ3771]Triple
不同情况的生成函数
我们先设
对于样例来说:
再设
对于样例来说:
解释一下
由于数据范围较大,需要用 FFT 或 NTT 优化
Problem
Description
我们讲一个悲伤的故事。
从前有一个贫穷的樵夫在河边砍柴。这时候河里出现了一个水神,夺过了他的斧头,说: “这把斧头,是不是你的?” 樵夫一看:“是啊是啊!”
水神把斧头扔在一边,又拿起一个东西问: “这把斧头,是不是你的?” 樵夫看不清楚,但又怕真的是自己的斧头,只好又答:“是啊是啊!”
水神又把手上的东西扔在一边,拿起第三个东西问: “这把斧头,是不是你的?” 樵夫还是看不清楚,但是他觉得再这样下去他就没法砍柴了。于是他又一次答:“是啊是啊!真的是!”
水神看着他,哈哈大笑道: “你看看你现在的样子,真是丑陋!” 之后就消失了。
樵夫觉得很坑爹,他今天不仅没有砍到柴,还丢了一把斧头给那个水神。于是他准备回家换一把斧头。
回家之后他才发现真正坑爹的事情才刚开始。水神拿着的的确是他的斧头。但是不一定是他拿出去的那把,还有可能是水神不知道怎么偷偷从他家里拿走的。换句话说,水神可能拿走了他的一把,两把或者三把斧头。
樵夫觉得今天真是倒霉透了,但不管怎么样日子还得过。他想统计他的损失。樵夫的每一把斧头都有一个价值,不同斧头的价值不同。总损失就是丢掉的斧头价值和。他想对于每个可能的总损失,计算有几种可能的方案。
注意:如果水神拿走了两把斧头
Input
第一行是整数
接下来
Output
若干行,按升序对于所有可能的总损失输出一行
Sample Input
44567
Sample Output
4 15 16 17 19 110 111 212 113 115 116 117 118 1
HINT
所有数据满足:
Code
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <complex>#include <cmath>using namespace std;typedef complex<double>cp;int rev[140005];cp a[140005],b[140005],c[140005],wi[140005],ans[140005];inline int Make(int n){ int i,L=log2(n)+1;n=1<<L; for(i=0;i<n;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1)); return n;}inline void FFT(cp A[],int n,int f){ int i,j,k; for(i=0;i<n;++i)if(rev[i]<i)swap(A[i],A[rev[i]]); for(i=1;i<n;i<<=1) { cp wn(cos(M_PI/i),f*sin(M_PI/i)); wi[0]=1; for(j=1;j<i;++j)wi[j]=wi[j-1]*wn; for(j=0;j<n;j+=i<<1) { for(k=0;k<i;++k) { cp x=A[j+k],y=wi[k]*A[i+j+k]; A[j+k]=x+y;A[i+j+k]=x-y; } } } if(f==-1)for(i=0;i<n;++i)A[i]=A[i]/double(n); return;}int main(void){ int i,x,n,m; scanf("%d",&n); for(i=1;i<=n;++i) { scanf("%d",&x); a[x]=b[x*2]=c[x*3]=cp(1,0); } m=Make(131071); FFT(a,m,1); FFT(b,m,1); FFT(c,m,1); for(i=0;i<m;++i) { ans[i]=a[i]+(a[i]*a[i]-b[i])/2.0+(a[i]*a[i]*a[i]-a[i]*b[i]*3.0+c[i]*2.0)/6.0; } FFT(ans,m,-1); for(i=0;i<m;++i) { if(ans[i].real()>0.9)printf("%d %.0f\n",i,round(ans[i].real())); } return 0;}