[Zjoi2014]力

題面

給出n個數qi,給出Fj的定義如下:

令Ei=Fi/qi,求Ei.

Input

第一行一個整數n。

接下來n行每行輸入一個數,第i行表示qi。

n≤100000,0<qi<1000000000

Output

 n行,第i行輸出Ei。與標準答案誤差不超過1e-2即可。

題解

有人說,這是一道快速傅里葉變換(FFT)板子題。

看到這個式子,感覺有點難,但是我們把Ei表示出來

F_{j}=\sum_{i<j}\frac{q_{i}q_{j}}{(j-i)^{2}}-\sum_{i>j}\frac{q_{i}q_{j}}{(i-j)^{2}}

E_{j}=\sum_{i<j}q_{i}\frac{1}{(j-i)^{2}}-\sum_{i>j}q_{i}\frac{1}{(i-j)^{2}}

把E拆開,

E_{j}=A_{j}-B_{j}

A_{j}=\sum_{i<j}q_{i}\frac{1}{(j-i)^{2}}\;,\; B_{j}=\sum_{i>j}q_{i}\frac{1}{(i-j)^{2}}

把右半邊求出來,設g_{i}=\frac{1}{i^{2}}\;,\;g_{0}=0,那麼A_{j}=\sum_{i\leq j}q_{i}g_{j-i}\;,\; B_{j}=\sum_{i\geq j}q_{i}g_{i-j},我們發現,A已經是卷積的形式了,可以用FFT做,

把B轉換一下,設B翻轉過來的數組爲B',q翻轉過來的數組爲q',那麼B'_{j}=\sum_{i\leq j}q'_{i}g_{i-j},就可以用FFT求B了。

CODE

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<cmath>
#include<algorithm>
#define LL long long
#define MAXN 200005
#pragma GCC optimize(2)
#pragma G++ optimize(3)
#define rg register
#define DB double
using namespace std;
inline int read() {
	int f = 1,x = 0;char s = getchar();
	while(s < '0' || s > '9') {if(s == '-') f = -1;s = getchar();}
	while(s >= '0' && s <= '9') {x = x * 10 + s - '0';s = getchar();}
	return x * f;
}
struct Omiga{
	DB a,b;
	inline Omiga(){a = b = 0.0;}
	inline Omiga(DB A,DB B){a = A,b = B;}
}w;
inline Omiga operator + (Omiga x,Omiga y) {
	return Omiga(x.a + y.a,x.b + y.b);
}
inline Omiga operator - (Omiga x,Omiga y) {
	return Omiga(x.a - y.a,x.b - y.b);
}
inline Omiga operator * (Omiga x,Omiga y) {
	return Omiga(x.a*y.a - x.b*y.b,x.a*y.b + x.b*y.a);
}
inline Omiga operator / (Omiga x,DB y) {
	return Omiga(x.a / y,x.b / y);
}
const DB PI = acos(-1);
int fan[MAXN*3];
inline void FFT(int len,Omiga *a,int temp) {
	int ugly = log2(len);
	fan[0] = 0;
	for(rg int i = 1;i < len;i ++) {
		fan[i] = (((fan[i>>1]>>1))|((i&1)<<(ugly-1)));
		if(fan[i] < i) swap(a[fan[i]],a[i]);
	}
	for(rg int k = 2;k <= len;k <<= 1) {
		int t = k / 2;
		Omiga vw(cos(temp*PI/t)*1.0,sin(temp*PI/t)*1.0);
		for(rg int i = 0;i < len;i += k) {
			Omiga w2(1.0,0.0);
			for(rg int j = 0;j < t;j ++,w2 = w2*vw) {
				Omiga w3 = a[i + j],w4 = a[i + j + t];
				a[i + j] = w3 + w4*w2;
				a[i + j + t] = w3 - w4*w2;
			}
		}
	}
	if(temp == -1) for(rg int i = 0;i <= len;i ++) {
		a[i] = a[i] / (DB)len;
	}
	return ;
}
int n,m,q,i,j,s,o,k,t;
Omiga F[MAXN*3],G[MAXN*3],AS[MAXN*3];
void juanji(Omiga *A,Omiga *B,Omiga *C,int lena,int lenb,int &lenc) {
	int nm = lena + lenb;
	int len = 1;
	len = 1<<(int)ceil(log2(nm));
	if(len==nm) len<<=1;
	FFT(len,A,1);FFT(len,B,1);
	for(rg int i = 0;i <= len;i ++) C[i] = A[i]*B[i];
	FFT(len,C,-1);
	lenc = len;
}
DB qi[MAXN];
DB ans[MAXN];
int main() {
	n = read();
	for(rg int i = 1;i <= n;i ++) {
		scanf("%lf",&qi[i]);
	}
	for(rg int i = 0;i < n;i ++) F[i].a = qi[i+1],F[i].b = 0.0;
	G[0].a = 0.0;G[0].b = 0.0;
	for(rg int i = 1;i < n;i ++) G[i].a = 1.0 / ((DB)i*i),G[i].b = 0.0;
	juanji(F,G,AS,n - 1,n - 1,m);
	for(rg int i = 0;i < n;i ++) {
		ans[i+1] += AS[i].a;
	}
	for(rg int i = 0;i <= m;i ++) F[i] = G[i] = AS[i] = w;
	for(rg int i = 0;i < n;i ++) F[i].a = qi[n - i],F[i].b = 0.0;
	G[0].a = 0.0;G[0].b = 0.0;
	for(rg int i = 1;i < n;i ++) G[i].a = 1.0 / ((DB)i*1.0*i),G[i].b = 0.0;
	juanji(F,G,AS,n - 1,n - 1,m);
	for(rg int i = 1;i <= n;i ++) {
		ans[i] -= AS[n - i].a;
	}
	for(rg int i = 1;i <= n;i ++) {
		printf("%.3lf\n",ans[i]);
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章