生活随笔
收集整理的這篇文章主要介紹了
P3338 [ZJOI2014]力 FFT + 推式子
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
傳送門
文章目錄
題意:
思路:
這個式子看起來很FFTFFTFFT,讓我們來化簡一下。
考慮EEE中直接將qiq_iqi?約掉,所以Ei=∑j=1i?1qj(i?j)2?∑j=i+1nqj(i?j)2E_i=\sum_{j=1}^{i-1}\frac{q_j}{(i-j)^2}-\sum_{j=i+1}^{n}\frac{q_j}{(i-j)^2}Ei?=j=1∑i?1?(i?j)2qj???j=i+1∑n?(i?j)2qj??
考慮將(i?j)2(i-j)^2(i?j)2簡化成一個數組來抽象的代替他,并令fi=qi,gi=1i2f_i=q_i,g_i=\frac{1}{i^2}fi?=qi?,gi?=i21?,所以式子變成了Ei=∑j=1i?1fj?gi?j?∑j=i+1nfj?gj?iE_i=\sum_{j=1}^{i-1}f_j*g_{i-j}-\sum_{j=i+1}^nf_j*g_{j-i}Ei?=j=1∑i?1?fj??gi?j??j=i+1∑n?fj??gj?i?
可以發現前部分就是一個卷積形式,直接卷一下即可,對于后部分我們還需要處理一下,向卷積的式子轉換。
∑j=i+1nfj?gj?i=∑j=1n?ifi+jgj\sum_{j=i+1}^nf_j*g_{j-i}=\sum_{j=1}^{n-i}f_{i+j}g_jj=i+1∑n?fj??gj?i?=j=1∑n?i?fi+j?gj?
看到n?in-in?i之后,就可以萌生一個很經典的做法,就是將fff翻轉一下,由于我們下標從111開始, 所以我們設f′[i]=f[n?i+1]f'[i]=f[n-i+1]f′[i]=f[n?i+1],所以式子變為了∑j=1n?ifi+jgj=∑j=1n?ifn?i?j?1′gj\sum_{j=1}^{n-i}f_{i+j}g_j=\sum_{j=1}^{n-i}f'_{n-i-j-1}g_jj=1∑n?i?fi+j?gj?=j=1∑n?i?fn?i?j?1′?gj?
考慮令t=n?i?1t=n-i-1t=n?i?1,所以式子變為∑j=1n?ifn?i?j?1′gj=∑i=1t+1ft?j′gj\sum_{j=1}^{n-i}f'_{n-i-j-1}g_j=\sum_{i=1}^{t+1}f'_{t-j}g_jj=1∑n?i?fn?i?j?1′?gj?=i=1∑t+1?ft?j′?gj?
這也是一個卷積形式,只需要偏移一個單位即可。
所以式子變成了Ei=∑j=1i?1fj?gi?j?∑i=1t+1ft?j′gjE_i=\sum_{j=1}^{i-1}f_j*g_{i-j}-\sum_{i=1}^{t+1}f'_{t-j}g_jEi?=j=1∑i?1?fj??gi?j??i=1∑t+1?ft?j′?gj?
直接正著反著卷一次即可。
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#include<random>
#include<cassert>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid ((tr[u].l+tr[u].r)>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std
;
typedef long long LL
;
typedef unsigned long long ULL
;
typedef pair
<int,int> PII
;const int N
=1000010,mod
=1e9+7,INF
=0x3f3f3f3f;
const double eps
=1e-6;int n
;
double g
[N
],f
[N
],sf
[N
];struct FFT {double PI
=acos(-1);int rev
[N
];int bit
,limit
;struct Complex {double x
,y
;void init() { x
=y
=0; }Complex
operator + (const Complex
& t
) const { return {x
+t
.x
,y
+t
.y
}; }Complex
operator - (const Complex
& t
) const { return {x
-t
.x
,y
-t
.y
}; }Complex
operator * (const Complex
& t
) const { return {x
*t
.x
-y
*t
.y
,x
*t
.y
+y
*t
.x
}; } }a
[N
],b
[N
],c
[N
];void init(int n
,int m
) {int x
=max(n
,m
)*2; bit
=0;while((1<<bit
)<=x
) bit
++;limit
=1<<bit
;for(int i
=0;i
<limit
;i
++) rev
[i
]=(rev
[i
>>1]>>1)|((i
&1)<<(bit
-1));}void fft(Complex a
[],int inv
) {for(int i
=0;i
<limit
;i
++) if(i
<rev
[i
]) swap(a
[i
],a
[rev
[i
]]);for(int mid
=1;mid
<limit
;mid
<<=1) {Complex w1
=Complex({cos(PI
/mid
),inv
*sin(PI
/mid
)});for(int i
=0;i
<limit
;i
+=mid
*2) {Complex wk
=Complex({1,0});for(int j
=0;j
<mid
;j
++,wk
=wk
*w1
) {Complex x
=a
[i
+j
],y
=wk
*a
[i
+j
+mid
];a
[i
+j
]=x
+y
; a
[i
+j
+mid
]=x
-y
;}}}if(inv
==-1) {for(int i
=0;i
<limit
;i
++) {a
[i
].x
/=limit
;a
[i
].y
/=limit
;}}}int solve(double *ans
,double *x
,int n
,double *y
,int m
,double *z
,int h
) {for(int i
=0;i
<=n
;i
++) a
[i
].x
=x
[i
];for(int i
=0;i
<=n
;i
++) b
[i
].x
=y
[i
];for(int i
=0;i
<=n
;i
++) c
[i
].x
=z
[i
];init(n
,m
); fft(a
,1); fft(b
,1); fft(c
,1);for(int i
=0;i
<limit
;i
++) a
[i
]=a
[i
]*c
[i
];for(int i
=0;i
<limit
;i
++) b
[i
]=b
[i
]*c
[i
];fft(a
,-1); fft(b
,-1);for(int i
=1;i
<=n
;i
++) ans
[i
]=a
[i
].x
-b
[n
-i
+1].x
;return n
+m
;}}FT
;int main()
{
cin
>>n
;for(int i
=1;i
<=n
;i
++) scanf("%lf",&f
[i
]),sf
[n
-i
+1]=f
[i
];for(int i
=1;i
<=n
;i
++) g
[i
]=(1.0/(1ll*i
*i
));int len
=FT
.solve(f
,f
,n
,sf
,n
,g
,n
);for(int i
=1;i
<=n
;i
++) printf("%.3f\n",f
[i
]);return 0;
}
總結
以上是生活随笔為你收集整理的P3338 [ZJOI2014]力 FFT + 推式子的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。