【题解】P3338 [ZJOI2014]力

题目描述

给出 n 个数 q1,q2,qn,定义

Fj = i=1j1qi×qj(ij)2  i=j+1nqi×qj(ij)2

Ei = Fiqi

1in,求 Ei 的值。
1n105

题解

对于乘积形式的式子计算,数据范围 105,应该想到 FFT 加速。于是开始推式子。
首先Ei=Fjqi=i=1j1qi(ij)2  i=j+1nqi(ij)2
f(i)=qi,g(i)=1i2,于是原式为Ei=i=1j1f(i)×g(ji)i=j+1nf(i)×g(ij)
左边已经是一个卷积的形式了,来看看右边。
卷积形式是从零开始的,我们要尽量将式子化成卷积。
于是更改求和为:i=0njf(j+i)×g(i)
接下来是一个经典套路,可以将式子翻转使得f(i)=f(ni),得到i=0njf((nj)i)×g(i)
两者都是卷积形式,fft$加速一下即可。
小结:

  • fft加速乘法卷积
  • 乘号两边同加减的可以翻转式子
#include<bits/stdc++.h>
using namespace std;
inline int rd(){
	int f=1,j=0;
	char w=getchar();
	while(!isdigit(w)){
		if(w=='-')f=-1;
		w=getchar(); 
	}
	while(isdigit(w)){
		j=j*10+w-'0';
		w=getchar();
	}
	return f*j;
}
const int N=400010;
const double pai=acos(-1);
int n,rev[N];
struct cp{
	double x,y;
	cp (double xx=0,double yy=0){x=xx,y=yy;}
	cp operator +(cp a){return cp(x+a.x,y+a.y);}
	cp operator -(cp a){return cp(x-a.x,y-a.y);}
	cp operator *(cp a){return cp(x*a.x-y*a.y,x*a.y+y*a.x);}
}a[N],b[N],c[N];
void fft(cp *f,int n,int flg){
	for(int i=0;i<n;i++)if(i<rev[i])swap(f[i],f[rev[i]]);
	for(int p=2;p<=n;p<<=1){
		int len=p>>1;
		cp tg(cos(2*pai/p),flg*sin(2*pai/p));
		for(int k=0;k<n;k+=p){
			cp buf(1,0);
			for(int l=k;l<k+len;l++){
				cp tt=buf*f[len+l];
				f[len+l]=f[l]-tt;
				f[l]=f[l]+tt;
				buf=buf*tg;
			}
		}
	}
	if(flg==-1)for(int i=0;i<n;i++)f[i].x/=n;
	return ;
}
signed main(){
	n=rd();
	for(int i=1;i<=n;i++){
		scanf("%lf",&a[i].x),c[n-i].x=a[i].x;
		b[i].x=1.0/i/i;
	}
	int lim=1,L=0;
	while(lim<=(n<<1))lim<<=1,L++;
	for(int i=0;i<lim;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1));
	fft(a,lim,1),fft(b,lim,1),fft(c,lim,1);
	for(int i=0;i<lim;i++)a[i]=a[i]*b[i],c[i]=c[i]*b[i];
	fft(a,lim,-1),fft(c,lim,-1);
	for(int i=1;i<=n;i++)printf("%.3lf\n",a[i].x-c[n-i].x);
	return 0;
}
posted @   flywatre  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示