BNUOJ 27935 我爱背单词 (加强版) (FFT)

来源:互联网 发布:c语言实验报告总结 编辑:程序博客网 时间:2024/04/29 23:37

题目链接:

BNUOJ 27935 - 我爱背单词 (中文题面)


分析:

原题数据范围很小,可以直接暴力计算新单词对每一天需要背的单词量的贡献,

注意到这个过程实质是一个多项式乘法,第Q天所需要背的单词量为多项式

(N[1]*x+N[2]*x^2+...+N[D]*x^D)(1+x^(R[1]-1)+x^(R[2]-1)+...+x^(R[k]-1))

展开式中x^Q项的系数,可以使用FFT算法进行求解。

优化后的算法可以处理更大范围的数据,视情形考虑使用不依赖浮点数精度的NTT算法。


代码:

#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<iostream>#include<algorithm>using namespace std;typedef double db;db PI=acos(-1.0);struct Complex{    db x,y;    Complex(db x=0.0,db y=0.0):x(x),y(y){}    Complex operator + (const Complex &b)const    {        return Complex(x+b.x,y+b.y);    }    Complex operator - (const Complex &b)const    {        return Complex(x-b.x,y-b.y);    }    Complex operator * (const Complex &b)const    {        return Complex(x*b.x-y*b.y,x*b.y+y*b.x);    }};void change(Complex y[],int len){    for(int i=1,j=len/2;i<len-1;i++)    {        if(i<j)swap(y[i],y[j]);        int k=len/2;        while(j>=k)        {            j-=k;            k/=2;        }        if(j<k)j+=k;    }}void fft(Complex y[],int len,int on){    change(y,len);    for(int h=2;h<=len;h<<=1)    {        Complex wn(cos(-on*2*PI/h),sin(-on*2*PI/h));        for(int j=0;j<len;j+=h)        {            Complex w(1,0);            for(int k=j;k<j+h/2;k++)            {                Complex u=y[k];                Complex t=w*y[k+h/2];                y[k]=u+t;                y[k+h/2]=u-t;                w=w*wn;            }        }    }    if(on==-1)        for(int i=0;i<len;i++)            y[i].x/=len;}const int MAXN=4096;Complex x1[MAXN],x2[MAXN];int N[105],R[105];int main(){    int T;    scanf("%d",&T);    while(T--)    {        int D;        scanf("%d",&D);        for(int i=1;i<=D;i++)scanf("%d",&N[i]);        int K;        scanf("%d",&K);        for(int i=1;i<=K;i++)scanf("%d",&R[i]);        memset(x1,0,sizeof(x1));        memset(x2,0,sizeof(x2));        for(int i=1;i<=D;i++)x1[i].x=N[i];        for(int i=1;i<=K;i++)x2[R[i]-1].x=1;        x2[0].x+=1;        fft(x1,MAXN,1);        fft(x2,MAXN,1);        for(int i=0;i<MAXN;i++)x1[i]=x1[i]*x2[i];        fft(x1,MAXN,-1);        int M;        scanf("%d",&M);        while(M--)        {            int Q;            scanf("%d",&Q);            if(Q>=MAXN)printf("0\n");            else printf("%d\n",(int)(x1[Q].x+0.5));        }    }    return 0;}


0 0
原创粉丝点击