把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P3338 [ZJOI2014]力

题面传送门
把那个\(q_j\)消掉就变成\(E_j=\sum\limits_{i=1}^{j}{\frac{q_i}{(i-j)^2}}-\sum\limits_{i=j}^{n}{\frac{q_i}{(i-j)^2}}\)
\(f_i=q_i\)\(g_i=\frac{1}{i^2}\),就有\(E_j=\sum\limits_{i=1}^{j}{f_i\times g_{j-i}}-\sum\limits_{i=j}^{n}{f_i\times g_{i-j}}\)
发现左边那个是个卷积,所以只要看右边那个即可。
整体平移一下就是\(\sum\limits_{i=0}^{n-j}{f_{i+j}\times g_i}\)
\(f'=f_{n-i}\)就有\(\sum\limits_{i=0}^{n-j}{f'_{n-i-j}\times g_i}\)
\(m=n-j\),那么就有\(\sum\limits_{i=0}^{m}{f'_{m-i}\times g_i}\)
这就是一个卷积的形式了。然后两次FFT即可。
code:

#include<cstdio>
#include<cmath>
#define db double
const db pi=acos(-1);
using namespace std;
int n,m,k,x,y,z,tr[400039];
struct Fs{
	db a,b;
	inline void make(db x,db y){a=x;b=y;}
	Fs operator +(const Fs &x){return (Fs){a+x.a,b+x.b};}
	Fs operator -(const Fs &x){return (Fs){a-x.a,b-x.b};}
	Fs operator *(const Fs &x){return (Fs){x.a*a-x.b*b,x.a*b+x.b*a};} 
}a[400039],b[400039],c[400039];
inline void swap(Fs &x,Fs &y){Fs tmp=x;x=y;y=tmp;}
inline void fft(Fs *f,int n,int flag){
    int i,j,k;Fs pus,key,now;
	for(i=0;i<n;i++)if(tr[i]>i) swap(f[tr[i]],f[i]);
	for(i=2;i<=n;i<<=1){
		for(key.make(cos(2*pi/i),flag*sin(2*pi/i)),j=0;j<n;j+=i){
			for(now.make(1,0),k=j;k<j+i/2;k++)pus=now*f[k+i/2],f[k+i/2]=f[k]-pus,f[k]=f[k]+pus,now=now*key;
		}
	}
}
int main(){
	freopen("1.in","r",stdin);
	register int i;
	scanf("%d",&n);for(m=1;m<=(n<<1);m<<=1);
	for(i=0;i<m;i++) tr[i]=(tr[i>>1]>>1)|((i&1)?(m>>1):0);
	for(i=1;i<=n;i++) scanf("%lf",&a[i].a),c[n-i].a=a[i].a,b[i].a=1.0/i/i;fft(a,m,1);fft(b,m,1);fft(c,m,1);
	for(i=0;i<m;i++) a[i]=a[i]*b[i],c[i]=c[i]*b[i];fft(a,m,-1);fft(c,m,-1);
	for(i=1;i<=n;i++) printf("%lf\n",a[i].a/m-c[n-i].a/m);
}
posted @ 2021-02-24 16:46  275307894a  阅读(29)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end