BZOJ3527: [Zjoi2014]力(洛谷P3338)

FFT

BZOJ题目传送门
洛谷题目传送门

推式子:

Ei=j=1i1qj(ij)2j=i+1nqj(ij)2=j=1i1f1(j)f2(ij)j=i+1nf1(j)f2(ij)(3)(4) (3) E i = ∑ j = 1 i − 1 q j ( i − j ) 2 − ∑ j = i + 1 n q j ( i − j ) 2 (4) = ∑ j = 1 i − 1 f 1 ( j ) f 2 ( i − j ) − ∑ j = i + 1 n f 1 ( j ) f 2 ( i − j )

其中 f1(x)=qx,f2(x)=1x2,f3(x)=f1(nx) f 1 ( x ) = q x , f 2 ( x ) = 1 x 2 , f 3 ( x ) = f 1 ( n − x )

h1(x)=xi=0f1(i)f2(xi),h2(nx)=nxi=0f2(i)f3(nix) h 1 ( x ) = ∑ i = 0 x f 1 ( i ) f 2 ( x − i ) , h 2 ( n − x ) = ∑ i = 0 n − x f 2 ( i ) f 3 ( n − i − x )

Ex=h1(x)h2(nx) E x = h 1 ( x ) − h 2 ( n − x )

然后搞FFT就好了

代码:

#include
#include
#include
#include
#define N 1<<18
#define F inline
using namespace std;
typedef double DB;
const DB pi=acos(-1);
struct P{ DB x,y; }f1[N],f2[N],f3[N];
int n,m,l,r[N];
F P operator + (P a,P b){ return (P){a.x+b.x,a.y+b.y}; }
F P operator - (P a,P b){ return (P){a.x-b.x,a.y-b.y}; }
F P operator * (P a,P b){ return (P){a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x}; }
F void FFT(P *a,int f){
    for (int i=0;iif (ifor (int k=1;k1){
        P w={1,0},wn={cos(pi/k),sin(f*pi/k)},x,y;
        for (int i=0;i1,w=(P){1,0})
            for (int j=0;jint main(){
    scanf("%d",&n),m=--n;
    for (int i=0;i<=n;i++)
        scanf("%lf",&f1[i].x),f3[n-i]=f1[i];
    for (int i=1;i<=n;i++) f2[i].x=1.0/i/i;
    for (n=1;n<=(m<<1);n<<=1) l++;
    for (int i=0;i//再也不加等于号了。。。
        r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    FFT(f1,1),FFT(f2,1),FFT(f3,1);
    for (int i=0;i1),FFT(f3,-1);
    for (int i=0;i<=m;i++)
        printf("%.3f\n",(f1[i].x-f3[m-i].x)/n);
    return 0;
}

你可能感兴趣的:(洛谷,BZOJ,数论---多项式相关,蒟蒻zxl的Blog专栏)