题目描述
给出n个数(q[i]),给出(F[i])的定义如下:
(F[i]=sum_{j=1}^{i-1}frac{q[i]*q[j]}{(i-j)^2}-sum_{j=i+1}^{j=n}frac{q[i]*q[j]}{(i-j)^2})
令(E[i]=frac{F[i]}{q[i]}),求(E[i]).
输入输出格式
输入格式:
第一行一个整数n。
接下来n行每行输入一个数,第i行表示qi。
输出格式:
n行,第i行输出Ei。
与标准答案误差不超过1e-2即可。
输入输出样例
输入样例#1:
5
4006373.885184
15375036.435759
1717456.469144
8514941.004912
1410681.345880
输出样例#1:
-16838672.693
3439.793
7509018.566
4595686.886
10903040.872
说明
对于30%的数据,n≤1000。
对于50%的数据,n≤60000。
对于100%的数据,n≤100000,0<qi<1000000000。
第一道FFT的题
看完题后感觉一脸懵逼
(???)
之后瞎化了一下然而并没有卵用
开心的看了题解
因为我们要求(E[i])
而(E[i] = frac{F[i]}{q[i]})
所以(E[i] = sum_{j=1}^{i-1}frac{q[j]}{(i-j)^2} - sum_{j=i+1}^{n}frac{q[j]}{(i-j)^2})
然后我们设(g[i]=frac{1}{i^2})
这样(E[i]=sum_{j=1}^{i-1}{q[j]*g[i-j]} - sum_{j=i+1}^{n}{q[j]*g[j-i]})
我们可以发现第一项满足卷积
所以第一项就直接把(q)和(g)卷起来取前n项就好辣
现在考虑第二项怎么化
设(j=i+k)
所以右边的式子就可以化成(sum_{k=1}^{n-i}{q[i+k]*g[k]})
然后我们可以把q数组翻转一下,设为(revq[i])
这样式子就成了(sum_{k=1}^{n-i}{revq[n-i-k]*g[k]})
满足卷积的基本形式,我们把(revq)和(g)卷起来取前n项就好辣
但是这次卷积的结果储存在n-i+1上,所以我们要从n开始反着与第一项作差
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
const int M = 400005 ;
using namespace std ;
const double Pi = acos(-1.0) ;
struct Complex {
double x , y ;
Complex (double Tx = 0 , double Ty = 0) { x = Tx , y = Ty ; }
}a[M] , b[M] ;
Complex operator + (Complex a , Complex b) {
return Complex (a.x + b.x , a.y + b.y) ;
}
Complex operator - (Complex a , Complex b) {
return Complex (a.x - b.x , a.y - b.y) ;
}
Complex operator * (Complex a , Complex b) {
return Complex (a.x * b.x - a.y * b.y , a.x * b.y + a.y * b.x) ;
}
int n ;
int l , r[M] , digital = 1 ;
double q[M] , fir[M] , sec[M] ;
inline void FFT(Complex *A , int unit) {
for(int i = 0 ; i < digital ; i ++)
if(r[i] > i)
swap(A[i] , A[r[i]]) ;
for(int mid = 1 ; mid < digital ; (mid <<= 1)) {
Complex W (cos(Pi / mid) , unit * sin(Pi / mid)) ;
int R = (mid << 1) ;
for(int j = 0 ; j < digital ; 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 + k + mid] = x - y ;
}
}
}
}
inline void Solve() {
while(digital <= n + n)
digital <<= 1 , ++l ;
for(int i = 0 ; i < digital ; i ++)
r[i] = (r[i>>1]>>1) | ((i&1)<<(l - 1)) ;
FFT(a , 1) ; FFT(b , 1) ;
for(int i = 0 ; i <= digital ; i ++) a[i] = a[i] * b[i] ;
FFT(a , -1) ;
}
int main() {
scanf("%d",&n) ;
for(int i = 1 ; i <= n ; i ++) scanf("%lf",&q[i]) ;
for(int i = 1 ; i <= n ; i ++) {
a[i].x = q[i] ;
b[i].x = 1.0 / (1.0 * i * i) ;
}
Solve() ;
for(int i = 1 ; i <= n ; i ++) fir[i] = a[i].x / ( 1.0 * digital );
digital = 1 ; l = 0 ;
memset(a , 0 , sizeof(a)) ; memset(b , 0 , sizeof(b)) ;
for(int i = 1 ; i <= (n>>1) ; i ++) swap(q[i] , q[n - i + 1]) ;
for(int i = 1 ; i <= n ; i ++) {
a[i].x = q[i] ;
b[i].x = 1.0/(1.0 * i * i) ;
}
Solve() ;
for(int i = 1 ; i <= n ; i ++) sec[i] = a[n - i + 1].x / ( 1.0 * digital );
for(int i = 1 ; i <= n ; i ++) printf("%.8lf
",fir[i] - sec[i]) ;
return 0 ;
}