【JZOJ3617】【ZJOI2014】力

╰( ̄▽ ̄)╭

這裏寫圖片描述
對於100%的數據,n100000;0<qi<1,000,000,000

(⊙ ▽ ⊙)

ri=1i2
Fj=j1i=0qirj1iGj=j1i=0qn1irji1
顯然Ei=FiGni1
F,G 的這樣的式子,我稱它爲卷積式

當滿足

f[j]=i=0j1a[i]b[j1i]

這樣的形式時,可以利用快速傅里葉變換
設多項式A 的係數分別爲a[0],a[1],a[2],...,a[j1]
多項式B 的係數分別爲b[0],b[1],b[2],...,b[j1]
則多項式C(C=AB) 的係數就分別爲f[0],f[1],f[2],...,f[j1]

( ̄~ ̄)

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<math.h>
#include<string.h>
#define ll long long
using namespace std;
const char* fin="ex3617.in";
const char* fout="ex3617.out";
const int inf=0x7fffffff;
const int maxn=500007;
const double pi=acos(-1);
struct Z{
    double x,y;
    Z(double _x=0,double _y=0){x=_x;y=_y;}
    Z operator +(const Z &a){return Z(x+a.x,y+a.y);}
    Z operator -(const Z &a){return Z(x-a.x,y-a.y);}
    Z operator *(const Z &a){return Z(x*a.x-y*a.y,x*a.y+y*a.x);}
}a[maxn],b[maxn],c[maxn],d[maxn];
int n,m,i,j,k,r[maxn];
void fft(Z *a,int sig){
    int i,j,k;
    for (i=0;i<n;i++) if (r[i]<i) swap(a[r[i]],a[i]);
    for (i=2;i<=n;i<<=1){
        int ha=i/2;
        for (j=0;j<ha;j++){
            Z w(cos(j*pi*sig/ha),sin(j*pi*sig/ha));
            for (k=j;k<n;k+=i){
                Z u=a[k],v=w*a[k+ha];
                a[k]=u+v;
                a[k+ha]=u-v;
            }
        }
    }
}
int main(){
    scanf("%d",&n);
    for (i=0;i<n;i++){
        scanf("%lf",&a[i].x);
        c[n-1-i].x=a[i].x;
    }
    for (i=1;i<n;i++) b[i]=1.0/i/i;
    m=n;
    k=0;
    for (n=1;n<m<<1;n<<=1) k++;
    for (i=0;i<n;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(k-1));

    fft(a,1);
    fft(c,1);
    fft(b,1);
    for (i=0;i<n;i++) a[i]=a[i]*b[i];
    for (i=0;i<n;i++) c[i]=c[i]*b[i];
    fft(a,-1);
    fft(c,-1);

    for (i=0;i<m;i++) printf("%lf\n",a[i].x/n-c[m-i-1].x/n);
    return 0;
}

(⊙v⊙)

1.

for (i=0;i<n;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(k-1));

這是一行很強的代碼,可以用於求出:二進制數ik 位意義上的倒轉r[i]
具體地,
採用遞推的形式,r[i] 可由r[i shr 1] 推得。
實質是ii shr 1二進制中十分相似,區別只在於i 多了一位數。

2.WARNING
最後的結果一定要/n

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