重走长征路---OI每周刷题记录---7月26日 2014

总目录详见https://blog.csdn.net/mrcrack/article/details/84471041

做题原则,找不到测评地址的题不做。2018-11-28

重走长征路---OI每周刷题记录---7月26日  2014

本周共计46题+题

测评地址:

数学:

1.「bzoj1011」[HNOI2008]遥远的行星

dp:

2.「FJ2014集训」折线统计(30分)

3.「czy系列赛」czy的后宫4 

4.「bzoj1643」[Usaco2007 Oct]Bessie’s Secret Pasture 贝茜的秘密草坪

5.「bzoj1633」[Usaco2007 Feb]The Cow Lexicon 牛的词典 

6.「cf451D」Count Good Substrings

7.「bzoj1649」[Usaco2006 Dec]Cow Roller Coaster 

8.「bzoj2201」彩色圆环

dp+树状数组:

9.「FJ2014集训」折线统计

二分+dp:

10.「czy系列赛」czy的后宫6

二进制:

11.「FJ2014集训」异或之

暴力:

12.「FJ2014集训」异或之(10分)

13. 「fj互测」二叉树(30分)

随机化:

14.「FJ2014集训」直线斯坦纳树

分块:

15.「bzoj2821」作诗(Poetize)

最小割:

16.「bzoj2561」最小生成树

fft:

17.「bzoj2179」FFT快速傅立叶   //在线测评地址https://www.luogu.org/problemnew/show/P1919

   47.【模板】多项式乘法(FFT)   //在线测评地址https://www.luogu.org/problemnew/show/P3803 

莫队算法:

18.「czy系列赛」czy的后宫3

spfa:

19.「cf449B」Jzzhu and Cities

数论+快速幂:

20.「fj夏令营」求和

模拟+二分:

21.「fj夏令营」解释器(70分)

dp+期望:

22.「fj夏令营」营销策略

背包dp:

23.「FJ2014集训」简单题(60分)

dfs:

24.「FJ2014集训」简单题(10分)

25.「FJ2014集训」愚蠢的算法(30分)

线段树+计算几何:

26.「FJ2014集训」信心题

上下界网络流:

27.「FJ2014集训」XWW的难题

lca:

28.「FJ2014集训」化合物(70分)

树链剖分+线段树:

29.「FJ2014集训」最短路

splay:

30.「bzoj1251」序列终结者*3 

31.「bzoj3223」JoyOI 1729 文艺平衡树 

32.NOI2005维修数列*2

kruskal:

33.「bzoj1682」Out of Hay 干草危机

状压dp:

34.「bzoj1688」[Usaco2005 Open]Disease Manangement 疾病管理

模拟:

35.「bzoj1637」[Usaco2007 Mar]Balanced Lineup

bfs:

36.「bzoj1615」[Usaco2008 Mar]The Loathesome Hay Baler麻烦的干草打包机

单调栈:

37.「bzoj1628」[Usaco2007 Demo]City skyline

二分+贪心:

38.「bzoj1650」[Usaco2006 Dec]River Hopscotch 跳石子

hall定理+线段树:

39.「FJ2014集训」圆桌会议

博弈论:

40.「cf451A」Game With Sticks

模拟:

41.「cf451B」 Sort the Array

42.「cf451C」Predict Outcome of the Game

乘法逆元+容斥原理+lucas定理:

43.「cf451E」Devu and Flowers

分块:

44.「bzoj2141」排队

dp:

45.「FJ互测」昊昊的机油之GRST(80分)

贪心:

46.「FJ互测」昊昊的机油之GRST

题解:

 

数学:

1.「bzoj1011」[HNOI2008]遥远的行星

dp:

2.「FJ2014集训」折线统计(30分)

3.「czy系列赛」czy的后宫4 

4.「bzoj1643」[Usaco2007 Oct]Bessie’s Secret Pasture 贝茜的秘密草坪

5.「bzoj1633」[Usaco2007 Feb]The Cow Lexicon 牛的词典 

6.「cf451D」Count Good Substrings

7.「bzoj1649」[Usaco2006 Dec]Cow Roller Coaster 

8.「bzoj2201」彩色圆环

dp+树状数组:

9.「FJ2014集训」折线统计

二分+dp:

10.「czy系列赛」czy的后宫6

二进制:

11.「FJ2014集训」异或之

暴力:

12.「FJ2014集训」异或之(10分)

13. 「fj互测」二叉树(30分)

随机化:

14.「FJ2014集训」直线斯坦纳树

分块:

15.「bzoj2821」作诗(Poetize)

最小割:

16.「bzoj2561」最小生成树

fft:

17.「bzoj2179」FFT快速傅立叶

//P1919 【模板】A*B Problem升级版(FFT快速傅里叶)
//在线测评地址https://www.luogu.org/problemnew/show/P1919 
//对应 7月26日 2014 
//n=60000,O(n^2)  60000^2=3.6*10^9高精度算法超时无疑 
//本题数据为洛谷自造数据,使用CYaRon耗时5分钟完成数据制作
//对上述比较感兴趣,抽空研究。2019-2-8 08:07 
//介绍FFT,此文不错https://blog.csdn.net/enjoy_pascal/article/details/81478582
//上文成型于作者初二升初三的暑假,研究了作者
//NOIP2016 普及组        复赛285 GD国一 初一 
//NOIP2017 提高组 初赛64 复赛340 GD国一 初二 
//NOIP2018 提高组        复赛314 GD国一 初三
//https://blog.csdn.net/ggn_2015/article/details/68922404此文FFT写得棒极了。 
//https://www.cnblogs.com/RabbitHu/p/FFT.html喜欢此文的代码。 
//不断的在前面3篇文章之间进行切换,弄懂了。 
//编写 朴素 FFT 即 递归 版本 
//C++ 因 用到 STL
//<complex> a[maxn],b[maxn],c[maxn],d[maxn];//此处写成<complex> a[maxn],b[maxn],c[maxn],d[maxn];//d作为临时空间
//不是很了解 复数 变量的定义。翻看他人代码,不行,不到山穷水尽绝不。
//打开头文件<complex>发现template<> class complex<double>;有点明白了,马上修改
//输入 
//6
//123456
//123456
//陌生度比较大的程序,代码需编写一段测试一段。 
//写成 printf("%d",(int)a[i].real());//写成 printf("%d",(int)a[i].real);//写成 printf("%d",(int)a[i]);//写成 printf("%d",a[i]);
//一个正确代码 printf("%d",(int)a[i].real());经历了3次,还是翻看头文件<complex>,发现const _Tp& real() const;才写全。 
//发现头文件<complex>有#include <cmath>,可以放心写PI=acos(-1);同时也测试了PI 
//样例没通过,排查,发现, 
//x=complex<double>(cos(i*2*PI/m),inv*sin(i*2*PI/m));//此处写成 x=(cos(i*2*PI/m),inv*sin(i*2*PI/m));
//修改,样例通过,测试数据 
//2
//11
//11
//121
//发现,没通过,排查 
//采用,静态对比代码的方式,发现 FFT(a,m,inv),FFT(a+m,m,inv);//此处写成 FFT(a,m,1),FFT(a+m,m,1); inv不该写死。
//修改,测试,上述样例还是无法通过,继续对比代码 
//x=complex<double>(cos(i*2*PI/n),inv*sin(i*2*PI/n));//此处写成x=complex<double>(cos(i*2*PI/m),inv*sin(i*2*PI/m));
//发现,如上,修改,自己的样例能通过了。 
//又测试了一组数据
//6
//123456
//123456
//15241383936
//顺利通过自制数据, 
//提交70分,测试点2,9,10RE,什么情况。  
//翻看他人代码,发现#define maxn 121000是同样的情况,怎么回事 
//仔细想了想while(n<len*2)n*=2;若len=60000,2*len=120000 2^16=65536 2^17=131072  121000RE是必然,必需大于131072 
//马上修改,#define maxn 121000改成#define maxn 140000
//提交AC。2019-2-10 13:47 朴树 FFT 递归算法。 
//数学好与编程好是两回事,但又彼此融合。
//用时2.5天,第1天,不知道FFT在讲什么。第2天,反复看资料,对着程序看资料,有点懂了。第3天,动手编,一些细节了解了。 
#include <cstdio>
#include <cstring>
#include <complex>
#define maxn 140000
using namespace std;
complex<double> a[maxn],b[maxn],d[maxn];//此处写成<complex> a[maxn],b[maxn],c[maxn],d[maxn];//d作为临时空间 
char sa[maxn/2],sb[maxn/2];
double PI;
int c[maxn];
void FFT(complex<double> *a,int n,int inv){//此处写成 void FFT(complex<double> *a,int n,int inv) 还是不熟悉 所致 
    int m=n/2,i;
    complex<double> x;
    if(n==1)return;//只有1项,不再处理。 
    for(i=0;i<m;i++)d[i]=a[i*2],d[i+m]=a[i*2+1];//分成奇偶项
    for(i=0;i<n;i++)a[i]=d[i];//存储回原数组 
    FFT(a,m,inv),FFT(a+m,m,inv);//此处写成 FFT(a,m,1),FFT(a+m,m,1); inv不该写死。 
    for(i=0;i<m;i++){
        x=complex<double>(cos(i*2*PI/n),inv*sin(i*2*PI/n));//此处写成x=complex<double>(cos(i*2*PI/m),inv*sin(i*2*PI/m));//此处写成 x=(cos(i*2*PI/m),inv*sin(i*2*PI/m));
        d[i]=a[i]+x*a[i+m],d[i+m]=a[i]-x*a[i+m];
    }
    for(i=0;i<n;i++)a[i]=d[i];
}
int main(){
    int len,i,n;
    memset(a,0,sizeof(a)),memset(b,0,sizeof(b)),memset(c,0,sizeof(c));
    scanf("%d",&len);  
    scanf("%s%s",sa,sb);//例,读入123456 
    for(i=0;i<len;i++)a[i]=sa[len-1-i]-'0',b[i]=sb[len-1-i]-'0';//例,读入123456,存储为654321  
    PI=acos(-1);
    n=1;
    while(n<len*2)n*=2;
    FFT(a,n,1);//系数转点值 
    FFT(b,n,1);//系数转点值
    for(i=0;i<n;i++)a[i]*=b[i];
    FFT(a,n,-1);//点值转系数
    for(i=0;i<n;i++){
        c[i]+=(int)(a[i].real()/n+0.5);
        c[i+1]+=c[i]/10;
        c[i]%=10;
    } 
    i=n-1;
    while(c[i]==0)i--;//去除前导0
    if(i==-1)printf("0");//全是0
    else{
        while(i>=0)printf("%d",c[i--]);
    } 
    return 0;

   47.【模板】多项式乘法(FFT)

版本6

//P3803 【模板】多项式乘法(FFT)
//在线测评地址https://www.luogu.org/problemnew/show/P3803 
//lena+lenb=2*10^6 2^20=1048576 2^21=2097152 空间需开到2100000 
//C++需用STL中的<complex> 
//才采用 朴素 FFT 递归版本,看几个点会TLE 
//if(n==1)return;//漏了此行,一直没有输出 递归一定要有出口。
//样例通过,提交11分,测试点1,3-8WA,9TLE.2019-2-10 17:03
//重新读题,发现输出一行n+m+1个数字 ,没说什么前导0的问题,看来想多了。
//将处理前导0的功能删除,输出部分,重新编写,提交11分,测试点1,3-9WA。2019-2-10 18:33
//翻看他人代码,发现问题出在输出上,输出未必是 整数啊,输出是浮点数 
//再看看一些代码,发现输出还是整数,只是输出格式做了控制,那么先做输出格式处理 
//提交,老样子,还是11分,2019-2-10 18:58
//将 double x; scanf("%lf",&x),统统改成 int
//提交,老样子,还是11分,2019-2-10 19:01
//n=10^6,n+1=1000001;m=10^6,m+1=1000001,n+1+m+1=2000002,2^21=2097152,最大开到2100000即可 
//随便找了个AC的代码进行提交,开始在提交代码中,找与本人写法类似的代码进行研究 
//以下为11分代码。2019-2-10 20:01 
//找打一个与本人类似的77分代码,进行研究 
//对比了才发现,该题一直在求系数,而非需要进位的乘法,本人一直在求乘法 
//系数可以大于10. 
//修改,提交我的代码终于77分了,提交的结果是88分,测试点9TLE。2019-2-10 20:23 
//好久没这么折腾了,一根筋绕不过来,以下为88分代码。
//朴素FFT算法遇到瓶颈,才有学习优化算法的动力。
//对 << 运算符 不熟悉的 可以 看以下两个例子

1<<0=1
1<<1=2
1<<2=4
1<<3=8
1<<4=16
1<<5=32
1<<6=64
1<<7=128
1<<8=256
1<<9=512
1<<10=1024

0<<1=0
1<<1=2
2<<1=4
3<<1=6
4<<1=8
5<<1=10
6<<1=12
7<<1=14
8<<1=16
9<<1=18
10<<1=20

//对 >> 运算符 不熟悉的 可以 看以下两个例子

0>>1=0
1>>1=0
2>>1=1
3>>1=1
4>>1=2
5>>1=2
6>>1=3
7>>1=3
8>>1=4
9>>1=4
10>>1=5

1>>0=1
1>>1=0
1>>2=0
1>>3=0
1>>4=0
1>>5=0
1>>6=0
1>>7=0
1>>8=0
1>>9=0
1>>10=0

//各位看到没,语言的学习,有人教 固然重要,但更重要的是自身的操练,实践。
//计算机语言的学习,与中文,英文的学习 方法基本类似。
//语言的学习,不是教出来的,而是自己实践出来的。2019-2-11 15:19 

//先写 迭代版 FFT 代码。
//样例未通过,跟踪代码发现if(i<t)swap(&a[i],&a[t]);//此处if一开始写在for(j=0内部,跟踪了程序,才发现写错位置 
//样例未通过,静态排查代码,发现m=k/2;//此处写成 m=n/2; 
//样例未通过,对比https://www.cnblogs.com/RabbitHu/p/FFT.html代码才发现 
//for(k=2;k<=n;k*=2){//此处写成for(k=2;k<n;k*=2),在初学阶段,很难独立查出 
//样例通过,提交44分,测试点5-9WA,什么情况。2019-2-11 22:30
//对比了代码发现,
//d[i+j]=a[i+j]+omg[n/k*j]*a[i+j+m];//此处写成d[i+j]=a[i+j]+omg[n*j/k]*a[i+j+m];当n=2000000,j=1000000,n*j在int范畴要溢出,真是危机四伏啊 
//d[i+j+m]=a[i+j]-omg[n/k*j]*a[i+j+m];//此处写成d[i+j]=a[i+j]-omg[n*j/k]*a[i+j+m];当n=2000000,j=1000000,n*j在int范畴要溢出,真是危机四伏啊 
//乘的时候要特别小心,容易int溢出。
//提交AC。2019-2-11 22:47 
//以下代码为  朴素版 FFT 递归代码 转 迭代版 FFT 代码。可以AC的代码,只是跑得偏慢。  

//脚步不停,继续优化 
//蝴蝶操作,看了https://www.cnblogs.com/RabbitHu/p/FFT.html发现这么简单,但想呢,确很困难。 
//马上修改,提交AC。明显快了很多。2019-2-11 23:02 
//以下为AC代码。 

//继续对主程序进行优化,准备删除 c[maxn]
//以下为删除c[maxn]后的AC代码。2019-2-11 23:07 

//引入rev[i]数组,可以在计算最后数列时,进行优化
//提交AC。发现,耗时明显减小。2019-2-11 23:32
//以下为进行 rev[i]数组 优化后代码。

//进行读入优化。
//样例通过,提交0分,全WA。好好查查怎么回事。
//对照代码,发现 
//while(c<'0'||c>'9'){if(c=='-')sign=-1;c=getchar();}//此处写成 while(c<'0'&&c>'9'){if(c=='-')sign=-1;c=getchar();}
//提交AC,发现时间确有减少,大数据量时,大约0.1s。 
//https://blog.csdn.net/c20190102/article/details/69710341参看此文,继续进行输出优化。 
//输出优化,提交11分,测试点1,3-9WA。 
//对比代码,发现putchar(x%10+'0');//此处写成 putchar(x+'0');
//可见,基本功怎么练都不过分。
//遇到新功能,多测试。 
//提交0分,全WA,发现print(123);测试代码未删除
//修改,提交AC。发现时间确有减少,大数据量时,大约0.1s。 
//以下为读入优化,输出优化后的AC代码。2019-2-12 13:09 

//进一步优化,不采用STL中的<complex>,自己编写
//样例通过,提交AC。总时间缩短了1s,质的飞跃。2019-2-12 16:24 
//以下为采用自己编写的complex的AC代码。 
#include <cstdio>
#include <cstring>
#include <cmath>
#define maxn 2100000
using namespace std;
struct complex{
    double x,y;
}a[maxn],b[maxn],omg[maxn],inv[maxn];
complex operator +(complex p,complex q){return (complex){p.x+q.x,p.y+q.y};}
complex operator -(complex p,complex q){return (complex){p.x-q.x,p.y-q.y};}
complex operator *(complex p,complex q){return (complex){p.x*q.x-p.y*q.y,p.x*q.y+p.y*q.x};}
complex operator /(complex p,double q){return (complex){p.x/q,p.y/q};}
int n,rev[maxn];//n总长度 
double PI;
void swap(complex *a,complex *b){
    complex t;
    t=*a,*a=*b,*b=t;
}
int read(){//读取优化 读入优化 
    int ret=0,sign=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')sign=-1;c=getchar();}//此处写成 while(c<'0'&&c>'9'){if(c=='-')sign=-1;c=getchar();}
    while('0'<=c&&c<='9'){ret=ret*10+c-'0',c=getchar();}//此处写成 while('0'<=c&&c<='9'){ret=ret*10+c-'0';}
    return ret*sign;
}
void print(int x){//输出优化 
    if(x<0)putchar('-'),x=-x;
    if(x>9)print(x/10);
    putchar(x%10+'0');//此处写成 putchar(x+'0');
}
void FFT(complex *a,complex *omg){
    int i,j,k,m;//bits数据的位数
    complex x;
    for(i=0;i<n;i++){//此处不能改成i<n/2,有反例,n=15,a11与a13互换 
        if(i<rev[i])swap(&a[i],&a[rev[i]]);//此处if一开始写在for(j=0内部,跟踪了程序,才发现写错位置//处理小序号 换 大序号。
    }
    for(k=2;k<=n;k*=2){//此处写成for(k=2;k<n;k*=2),在初学阶段,很难独立查出//每块大小为2,4,8,16...的处理 
        m=k/2;//此处写成 m=n/2;
        for(i=0;i<n;i+=k)//处理完长度为n的序列,每块数据跳跃为k 
            for(j=0;j<m;j++){//每块分半处理,即处理前m个数据,后m个数据
                x=omg[n/k*j]*a[i+j+m];
                a[i+j+m]=a[i+j]-x;//此处写成d[i+j]=a[i+j]-omg[n*j/k]*a[i+j+m];当n=2000000,j=1000000,n*j在int范畴要溢出,真是危机四伏啊
                a[i+j]=a[i+j]+x;//此处写成d[i+j]=a[i+j]+omg[n*j/k]*a[i+j+m];当n=2000000,j=1000000,n*j在int范畴要溢出,真是危机四伏啊 
            } 
    }
}
void init(){
    int i,t,bits=0,j;
    PI=acos(-1);
    for(i=0;i<n;i++){
        omg[i]=(complex){cos(2*PI*i/n),sin(2*PI*i/n)};
        inv[i]=(complex){cos(2*PI*i/n),-sin(2*PI*i/n)};
    }
    while((1<<bits)<n)bits++; 
    for(i=0;i<n;i++){//此处不能改成i<n/2,有反例,n=15,a11与a13互换 
        t=0;
        for(j=0;j<bits;j++)if((i>>j)&1)t|=(1<<(bits-1-j));//t为i的翻转二进制 如i=001,t=100
        rev[i]=t;
    }
}
int main(){
    int lena,lenb,i;
    int x;
    memset(a,0,sizeof(a)),memset(b,0,sizeof(b));
    lena=read(),lenb=read();
    lena+=1,lenb+=1;
    for(i=0;i<lena;i++)x=read(),a[i].x=x;//此处写成 for(i=0;i<lena;i++)scanf("%lf",&a[i]);
    for(i=0;i<lenb;i++)x=read(),b[i].x=x;//此处写成 for(i=0;i<lenb;i++)scanf("%lf",&b[i]);
    n=1;
    while(n<lena+lenb)n*=2;
    init();
    FFT(a,omg),FFT(b,omg);//系数化点值
    for(i=0;i<n;i++)a[i]=a[i]*b[i];
    FFT(a,inv);//点值化系数
    print((int)(a[0].x/n+0.5));//系数可以大于10.
    for(i=1;i<lena-1+lenb-1+1;i++)putchar(' '),print((int)(a[i].x/n+0.5));
    putchar('\n');
    return 0;
}
 

版本5

//P3803 【模板】多项式乘法(FFT)
//在线测评地址https://www.luogu.org/problemnew/show/P3803 
//lena+lenb=2*10^6 2^20=1048576 2^21=2097152 空间需开到2100000 
//C++需用STL中的<complex> 
//才采用 朴素 FFT 递归版本,看几个点会TLE 
//if(n==1)return;//漏了此行,一直没有输出 递归一定要有出口。
//样例通过,提交11分,测试点1,3-8WA,9TLE.2019-2-10 17:03
//重新读题,发现输出一行n+m+1个数字 ,没说什么前导0的问题,看来想多了。
//将处理前导0的功能删除,输出部分,重新编写,提交11分,测试点1,3-9WA。2019-2-10 18:33
//翻看他人代码,发现问题出在输出上,输出未必是 整数啊,输出是浮点数 
//再看看一些代码,发现输出还是整数,只是输出格式做了控制,那么先做输出格式处理 
//提交,老样子,还是11分,2019-2-10 18:58
//将 double x; scanf("%lf",&x),统统改成 int
//提交,老样子,还是11分,2019-2-10 19:01
//n=10^6,n+1=1000001;m=10^6,m+1=1000001,n+1+m+1=2000002,2^21=2097152,最大开到2100000即可 
//随便找了个AC的代码进行提交,开始在提交代码中,找与本人写法类似的代码进行研究 
//以下为11分代码。2019-2-10 20:01 
//找打一个与本人类似的77分代码,进行研究 
//对比了才发现,该题一直在求系数,而非需要进位的乘法,本人一直在求乘法 
//系数可以大于10. 
//修改,提交我的代码终于77分了,提交的结果是88分,测试点9TLE。2019-2-10 20:23 
//好久没这么折腾了,一根筋绕不过来,以下为88分代码。
//朴素FFT算法遇到瓶颈,才有学习优化算法的动力。
//对 << 运算符 不熟悉的 可以 看以下两个例子

1<<0=1
1<<1=2
1<<2=4
1<<3=8
1<<4=16
1<<5=32
1<<6=64
1<<7=128
1<<8=256
1<<9=512
1<<10=1024

0<<1=0
1<<1=2
2<<1=4
3<<1=6
4<<1=8
5<<1=10
6<<1=12
7<<1=14
8<<1=16
9<<1=18
10<<1=20

//对 >> 运算符 不熟悉的 可以 看以下两个例子

0>>1=0
1>>1=0
2>>1=1
3>>1=1
4>>1=2
5>>1=2
6>>1=3
7>>1=3
8>>1=4
9>>1=4
10>>1=5

1>>0=1
1>>1=0
1>>2=0
1>>3=0
1>>4=0
1>>5=0
1>>6=0
1>>7=0
1>>8=0
1>>9=0
1>>10=0

//各位看到没,语言的学习,有人教 固然重要,但更重要的是自身的操练,实践。
//计算机语言的学习,与中文,英文的学习 方法基本类似。
//语言的学习,不是教出来的,而是自己实践出来的。2019-2-11 15:19 

//先写 迭代版 FFT 代码。
//样例未通过,跟踪代码发现if(i<t)swap(&a[i],&a[t]);//此处if一开始写在for(j=0内部,跟踪了程序,才发现写错位置 
//样例未通过,静态排查代码,发现m=k/2;//此处写成 m=n/2; 
//样例未通过,对比https://www.cnblogs.com/RabbitHu/p/FFT.html代码才发现 
//for(k=2;k<=n;k*=2){//此处写成for(k=2;k<n;k*=2),在初学阶段,很难独立查出 
//样例通过,提交44分,测试点5-9WA,什么情况。2019-2-11 22:30
//对比了代码发现,
//d[i+j]=a[i+j]+omg[n/k*j]*a[i+j+m];//此处写成d[i+j]=a[i+j]+omg[n*j/k]*a[i+j+m];当n=2000000,j=1000000,n*j在int范畴要溢出,真是危机四伏啊 
//d[i+j+m]=a[i+j]-omg[n/k*j]*a[i+j+m];//此处写成d[i+j]=a[i+j]-omg[n*j/k]*a[i+j+m];当n=2000000,j=1000000,n*j在int范畴要溢出,真是危机四伏啊 
//乘的时候要特别小心,容易int溢出。
//提交AC。2019-2-11 22:47 
//以下代码为  朴素版 FFT 递归代码 转 迭代版 FFT 代码。可以AC的代码,只是跑得偏慢。  

//脚步不停,继续优化 
//蝴蝶操作,看了https://www.cnblogs.com/RabbitHu/p/FFT.html发现这么简单,但想呢,确很困难。 
//马上修改,提交AC。明显快了很多。2019-2-11 23:02 
//以下为AC代码。 

//继续对主程序进行优化,准备删除 c[maxn]
//以下为删除c[maxn]后的AC代码。2019-2-11 23:07 

//引入rev[i]数组,可以在计算最后数列时,进行优化
//提交AC。发现,耗时明显减小。2019-2-11 23:32
//以下为进行 rev[i]数组 优化后代码。

//进行读入优化。
//样例通过,提交0分,全WA。好好查查怎么回事。
//对照代码,发现 
//while(c<'0'||c>'9'){if(c=='-')sign=-1;c=getchar();}//此处写成 while(c<'0'&&c>'9'){if(c=='-')sign=-1;c=getchar();}
//提交AC,发现时间确有减少,大数据量时,大约0.1s。 
//https://blog.csdn.net/c20190102/article/details/69710341参看此文,继续进行输出优化。 
//输出优化,提交11分,测试点1,3-9WA。 
//对比代码,发现putchar(x%10+'0');//此处写成 putchar(x+'0');
//可见,基本功怎么练都不过分。
//遇到新功能,多测试。 
//提交0分,全WA,发现print(123);测试代码未删除
//修改,提交AC。发现时间确有减少,大数据量时,大约0.1s。 
//以下为读入优化,输出优化后的AC代码。2019-2-12 13:09 
#include <cstdio>
#include <cstring>
#include <complex>
#define maxn 2100000
using namespace std;
complex<double> a[maxn],b[maxn],omg[maxn],inv[maxn];
int n,rev[maxn];//n总长度 
double PI;
void swap(complex<double> *a,complex<double> *b){
    complex<double> t;
    t=*a,*a=*b,*b=t;
}
int read(){//读取优化 读入优化 
    int ret=0,sign=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')sign=-1;c=getchar();}//此处写成 while(c<'0'&&c>'9'){if(c=='-')sign=-1;c=getchar();}
    while('0'<=c&&c<='9'){ret=ret*10+c-'0',c=getchar();}//此处写成 while('0'<=c&&c<='9'){ret=ret*10+c-'0';}
    return ret*sign;
}
void print(int x){//输出优化 
    if(x<0)putchar('-'),x=-x;
    if(x>9)print(x/10);
    putchar(x%10+'0');//此处写成 putchar(x+'0');
}
void FFT(complex<double> *a,complex<double> *omg){
    int i,j,k,m;//bits数据的位数
    complex<double> x;
    for(i=0;i<n;i++){//此处不能改成i<n/2,有反例,n=15,a11与a13互换 
        if(i<rev[i])swap(&a[i],&a[rev[i]]);//此处if一开始写在for(j=0内部,跟踪了程序,才发现写错位置//处理小序号 换 大序号。
    }
    for(k=2;k<=n;k*=2){//此处写成for(k=2;k<n;k*=2),在初学阶段,很难独立查出//每块大小为2,4,8,16...的处理 
        m=k/2;//此处写成 m=n/2;
        for(i=0;i<n;i+=k)//处理完长度为n的序列,每块数据跳跃为k 
            for(j=0;j<m;j++){//每块分半处理,即处理前m个数据,后m个数据
                x=omg[n/k*j]*a[i+j+m];
                a[i+j+m]=a[i+j]-x;//此处写成d[i+j]=a[i+j]-omg[n*j/k]*a[i+j+m];当n=2000000,j=1000000,n*j在int范畴要溢出,真是危机四伏啊
                a[i+j]=a[i+j]+x;//此处写成d[i+j]=a[i+j]+omg[n*j/k]*a[i+j+m];当n=2000000,j=1000000,n*j在int范畴要溢出,真是危机四伏啊 
            } 
    }
}
void init(){
    int i,t,bits=0,j;
    PI=acos(-1);
    for(i=0;i<n;i++){
        omg[i]=complex<double>(cos(2*PI*i/n),sin(2*PI*i/n));
        inv[i]=complex<double>(cos(2*PI*i/n),-sin(2*PI*i/n));
    }
    while((1<<bits)<n)bits++; 
    for(i=0;i<n;i++){//此处不能改成i<n/2,有反例,n=15,a11与a13互换 
        t=0;
        for(j=0;j<bits;j++)if((i>>j)&1)t|=(1<<(bits-1-j));//t为i的翻转二进制 如i=001,t=100
        rev[i]=t;
    }
}
int main(){
    int lena,lenb,i;
    int x;
    memset(a,0,sizeof(a)),memset(b,0,sizeof(b));
    lena=read(),lenb=read();
    lena+=1,lenb+=1;
    for(i=0;i<lena;i++)x=read(),a[i]=x;//此处写成 for(i=0;i<lena;i++)scanf("%lf",&a[i]);
    for(i=0;i<lenb;i++)x=read(),b[i]=x;//此处写成 for(i=0;i<lenb;i++)scanf("%lf",&b[i]);
    n=1;
    while(n<lena+lenb)n*=2;
    init();
    FFT(a,omg),FFT(b,omg);//系数化点值
    for(i=0;i<n;i++)a[i]*=b[i];
    FFT(a,inv);//点值化系数
    print((int)(a[0].real()/n+0.5));//系数可以大于10.
    for(i=1;i<lena-1+lenb-1+1;i++)putchar(' '),print((int)(a[i].real()/n+0.5));
    putchar('\n');
    return 0;
}
 

//P3803 【模板】多项式乘法(FFT)
//在线测评地址https://www.luogu.org/problemnew/show/P3803 
//lena+lenb=2*10^6 2^20=1048576 2^21=2097152 空间需开到2100000 
//C++需用STL中的<complex> 
//才采用 朴素 FFT 递归版本,看几个点会TLE 
//if(n==1)return;//漏了此行,一直没有输出 递归一定要有出口。
//样例通过,提交11分,测试点1,3-8WA,9TLE.2019-2-10 17:03
//重新读题,发现输出一行n+m+1个数字 ,没说什么前导0的问题,看来想多了。
//将处理前导0的功能删除,输出部分,重新编写,提交11分,测试点1,3-9WA。2019-2-10 18:33
//翻看他人代码,发现问题出在输出上,输出未必是 整数啊,输出是浮点数 
//再看看一些代码,发现输出还是整数,只是输出格式做了控制,那么先做输出格式处理 
//提交,老样子,还是11分,2019-2-10 18:58
//将 double x; scanf("%lf",&x),统统改成 int
//提交,老样子,还是11分,2019-2-10 19:01
//n=10^6,n+1=1000001;m=10^6,m+1=1000001,n+1+m+1=2000002,2^21=2097152,最大开到2100000即可 
//随便找了个AC的代码进行提交,开始在提交代码中,找与本人写法类似的代码进行研究 
//以下为11分代码。2019-2-10 20:01 
//找打一个与本人类似的77分代码,进行研究 
//对比了才发现,该题一直在求系数,而非需要进位的乘法,本人一直在求乘法 
//系数可以大于10. 
//修改,提交我的代码终于77分了,提交的结果是88分,测试点9TLE。2019-2-10 20:23 
//好久没这么折腾了,一根筋绕不过来,以下为88分代码。
//朴素FFT算法遇到瓶颈,才有学习优化算法的动力。
//对 << 运算符 不熟悉的 可以 看以下两个例子

1<<0=1
1<<1=2
1<<2=4
1<<3=8
1<<4=16
1<<5=32
1<<6=64
1<<7=128
1<<8=256
1<<9=512
1<<10=1024

0<<1=0
1<<1=2
2<<1=4
3<<1=6
4<<1=8
5<<1=10
6<<1=12
7<<1=14
8<<1=16
9<<1=18
10<<1=20

//对 >> 运算符 不熟悉的 可以 看以下两个例子

0>>1=0
1>>1=0
2>>1=1
3>>1=1
4>>1=2
5>>1=2
6>>1=3
7>>1=3
8>>1=4
9>>1=4
10>>1=5

1>>0=1
1>>1=0
1>>2=0
1>>3=0
1>>4=0
1>>5=0
1>>6=0
1>>7=0
1>>8=0
1>>9=0
1>>10=0

//各位看到没,语言的学习,有人教 固然重要,但更重要的是自身的操练,实践。
//计算机语言的学习,与中文,英文的学习 方法基本类似。
//语言的学习,不是教出来的,而是自己实践出来的。2019-2-11 15:19 

//先写 迭代版 FFT 代码。
//样例未通过,跟踪代码发现if(i<t)swap(&a[i],&a[t]);//此处if一开始写在for(j=0内部,跟踪了程序,才发现写错位置 
//样例未通过,静态排查代码,发现m=k/2;//此处写成 m=n/2; 
//样例未通过,对比https://www.cnblogs.com/RabbitHu/p/FFT.html代码才发现 
//for(k=2;k<=n;k*=2){//此处写成for(k=2;k<n;k*=2),在初学阶段,很难独立查出 
//样例通过,提交44分,测试点5-9WA,什么情况。2019-2-11 22:30
//对比了代码发现,
//d[i+j]=a[i+j]+omg[n/k*j]*a[i+j+m];//此处写成d[i+j]=a[i+j]+omg[n*j/k]*a[i+j+m];当n=2000000,j=1000000,n*j在int范畴要溢出,真是危机四伏啊 
//d[i+j+m]=a[i+j]-omg[n/k*j]*a[i+j+m];//此处写成d[i+j]=a[i+j]-omg[n*j/k]*a[i+j+m];当n=2000000,j=1000000,n*j在int范畴要溢出,真是危机四伏啊 
//乘的时候要特别小心,容易int溢出。
//提交AC。2019-2-11 22:47 
//以下代码为  朴素版 FFT 递归代码 转 迭代版 FFT 代码。可以AC的代码,只是跑得偏慢。  

//脚步不停,继续优化 
//蝴蝶操作,看了https://www.cnblogs.com/RabbitHu/p/FFT.html发现这么简单,但想呢,确很困难。 
//马上修改,提交AC。明显快了很多。2019-2-11 23:02 
//以下为AC代码。 

//继续对主程序进行优化,准备删除 c[maxn]
//以下为删除c[maxn]后的AC代码。2019-2-11 23:07 

//引入rev[i]数组,可以在计算最后数列时,进行优化
//提交AC。发现,耗时明显减小。2019-2-11 23:32
//以下为进行 rev[i]数组 优化后代码。 
#include <cstdio>
#include <cstring>
#include <complex>
#define maxn 2100000
using namespace std;
complex<double> a[maxn],b[maxn],omg[maxn],inv[maxn];
int n,rev[maxn];//n总长度 
double PI;
void swap(complex<double> *a,complex<double> *b){
    complex<double> t;
    t=*a,*a=*b,*b=t;
}
void FFT(complex<double> *a,complex<double> *omg){
    int i,j,k,m;//bits数据的位数
    complex<double> x;
    for(i=0;i<n;i++){//此处不能改成i<n/2,有反例,n=15,a11与a13互换 
        if(i<rev[i])swap(&a[i],&a[rev[i]]);//此处if一开始写在for(j=0内部,跟踪了程序,才发现写错位置//处理小序号 换 大序号。
    }
    for(k=2;k<=n;k*=2){//此处写成for(k=2;k<n;k*=2),在初学阶段,很难独立查出//每块大小为2,4,8,16...的处理 
        m=k/2;//此处写成 m=n/2;
        for(i=0;i<n;i+=k)//处理完长度为n的序列,每块数据跳跃为k 
            for(j=0;j<m;j++){//每块分半处理,即处理前m个数据,后m个数据
                x=omg[n/k*j]*a[i+j+m];
                a[i+j+m]=a[i+j]-x;//此处写成d[i+j]=a[i+j]-omg[n*j/k]*a[i+j+m];当n=2000000,j=1000000,n*j在int范畴要溢出,真是危机四伏啊
                a[i+j]=a[i+j]+x;//此处写成d[i+j]=a[i+j]+omg[n*j/k]*a[i+j+m];当n=2000000,j=1000000,n*j在int范畴要溢出,真是危机四伏啊 
            } 
    }
}
void init(){
    int i,t,bits=0,j;
    PI=acos(-1);
    for(i=0;i<n;i++){
        omg[i]=complex<double>(cos(2*PI*i/n),sin(2*PI*i/n));
        inv[i]=complex<double>(cos(2*PI*i/n),-sin(2*PI*i/n));
    }
    while((1<<bits)<n)bits++; 
    for(i=0;i<n;i++){//此处不能改成i<n/2,有反例,n=15,a11与a13互换 
        t=0;
        for(j=0;j<bits;j++)if((i>>j)&1)t|=(1<<(bits-1-j));//t为i的翻转二进制 如i=001,t=100
        rev[i]=t;
    }
}
int main(){
    int lena,lenb,i;
    int x;
    memset(a,0,sizeof(a)),memset(b,0,sizeof(b));
    scanf("%d%d",&lena,&lenb);
    lena+=1,lenb+=1;
    for(i=0;i<lena;i++)scanf("%d",&x),a[i]=x;//此处写成 for(i=0;i<lena;i++)scanf("%lf",&a[i]);
    for(i=0;i<lenb;i++)scanf("%d",&x),b[i]=x;//此处写成 for(i=0;i<lenb;i++)scanf("%lf",&b[i]);
    n=1;
    while(n<lena+lenb)n*=2;
    init();
    FFT(a,omg),FFT(b,omg);//系数化点值
    for(i=0;i<n;i++)a[i]*=b[i];
    FFT(a,inv);//点值化系数
    printf("%d",(int)(a[0].real()/n+0.5));//系数可以大于10.
    for(i=1;i<lena-1+lenb-1+1;i++)printf(" %d",(int)(a[i].real()/n+0.5));
    printf("\n");
    return 0;
}
 

版本4

//P3803 【模板】多项式乘法(FFT)
//在线测评地址https://www.luogu.org/problemnew/show/P3803 
//lena+lenb=2*10^6 2^20=1048576 2^21=2097152 空间需开到2100000 
//C++需用STL中的<complex> 
//才采用 朴素 FFT 递归版本,看几个点会TLE 
//if(n==1)return;//漏了此行,一直没有输出 递归一定要有出口。
//样例通过,提交11分,测试点1,3-8WA,9TLE.2019-2-10 17:03
//重新读题,发现输出一行n+m+1个数字 ,没说什么前导0的问题,看来想多了。
//将处理前导0的功能删除,输出部分,重新编写,提交11分,测试点1,3-9WA。2019-2-10 18:33
//翻看他人代码,发现问题出在输出上,输出未必是 整数啊,输出是浮点数 
//再看看一些代码,发现输出还是整数,只是输出格式做了控制,那么先做输出格式处理 
//提交,老样子,还是11分,2019-2-10 18:58
//将 double x; scanf("%lf",&x),统统改成 int
//提交,老样子,还是11分,2019-2-10 19:01
//n=10^6,n+1=1000001;m=10^6,m+1=1000001,n+1+m+1=2000002,2^21=2097152,最大开到2100000即可 
//随便找了个AC的代码进行提交,开始在提交代码中,找与本人写法类似的代码进行研究 
//以下为11分代码。2019-2-10 20:01 
//找打一个与本人类似的77分代码,进行研究 
//对比了才发现,该题一直在求系数,而非需要进位的乘法,本人一直在求乘法 
//系数可以大于10. 
//修改,提交我的代码终于77分了,提交的结果是88分,测试点9TLE。2019-2-10 20:23 
//好久没这么折腾了,一根筋绕不过来,以下为88分代码。
//朴素FFT算法遇到瓶颈,才有学习优化算法的动力。
//对 << 运算符 不熟悉的 可以 看以下两个例子

1<<0=1
1<<1=2
1<<2=4
1<<3=8
1<<4=16
1<<5=32
1<<6=64
1<<7=128
1<<8=256
1<<9=512
1<<10=1024

0<<1=0
1<<1=2
2<<1=4
3<<1=6
4<<1=8
5<<1=10
6<<1=12
7<<1=14
8<<1=16
9<<1=18
10<<1=20

//对 >> 运算符 不熟悉的 可以 看以下两个例子

0>>1=0
1>>1=0
2>>1=1
3>>1=1
4>>1=2
5>>1=2
6>>1=3
7>>1=3
8>>1=4
9>>1=4
10>>1=5

1>>0=1
1>>1=0
1>>2=0
1>>3=0
1>>4=0
1>>5=0
1>>6=0
1>>7=0
1>>8=0
1>>9=0
1>>10=0

//各位看到没,语言的学习,有人教 固然重要,但更重要的是自身的操练,实践。
//计算机语言的学习,与中文,英文的学习 方法基本类似。
//语言的学习,不是教出来的,而是自己实践出来的。2019-2-11 15:19 

//先写 迭代版 FFT 代码。
//样例未通过,跟踪代码发现if(i<t)swap(&a[i],&a[t]);//此处if一开始写在for(j=0内部,跟踪了程序,才发现写错位置 
//样例未通过,静态排查代码,发现m=k/2;//此处写成 m=n/2; 
//样例未通过,对比https://www.cnblogs.com/RabbitHu/p/FFT.html代码才发现 
//for(k=2;k<=n;k*=2){//此处写成for(k=2;k<n;k*=2),在初学阶段,很难独立查出 
//样例通过,提交44分,测试点5-9WA,什么情况。2019-2-11 22:30
//对比了代码发现,
//d[i+j]=a[i+j]+omg[n/k*j]*a[i+j+m];//此处写成d[i+j]=a[i+j]+omg[n*j/k]*a[i+j+m];当n=2000000,j=1000000,n*j在int范畴要溢出,真是危机四伏啊 
//d[i+j+m]=a[i+j]-omg[n/k*j]*a[i+j+m];//此处写成d[i+j]=a[i+j]-omg[n*j/k]*a[i+j+m];当n=2000000,j=1000000,n*j在int范畴要溢出,真是危机四伏啊 
//乘的时候要特别小心,容易int溢出。
//提交AC。2019-2-11 22:47 
//以下代码为  朴素版 FFT 递归代码 转 迭代版 FFT 代码。可以AC的代码,只是跑得偏慢。  

//脚步不停,继续优化 
//蝴蝶操作,看了https://www.cnblogs.com/RabbitHu/p/FFT.html发现这么简单,但想呢,确很困难。 
//马上修改,提交AC。明显快了很多。2019-2-11 23:02 
//以下为AC代码。 

//继续对主程序进行优化,准备删除 c[maxn]
//以下为删除c[maxn]后的AC代码。2019-2-11 23:07 
#include <cstdio>
#include <cstring>
#include <complex>
#define maxn 2100000
using namespace std;
complex<double> a[maxn],b[maxn],omg[maxn],inv[maxn];
int n;//n总长度 
double PI;
void swap(complex<double> *a,complex<double> *b){
    complex<double> t;
    t=*a,*a=*b,*b=t;
}
void FFT(complex<double> *a,complex<double> *omg){
    int i,j,k,t,bits=0,m;//bits数据的位数
    complex<double> x;
    while((1<<bits)<n)bits++; 
    for(i=0;i<n;i++){//此处不能改成i<n/2,有反例,n=15,a11与a13互换 
        t=0;
        for(j=0;j<bits;j++)if((i>>j)&1)t|=(1<<(bits-1-j));//t为i的翻转二进制 如i=001,t=100
        if(i<t)swap(&a[i],&a[t]);//此处if一开始写在for(j=0内部,跟踪了程序,才发现写错位置//处理小序号 换 大序号。
    }
    for(k=2;k<=n;k*=2){//此处写成for(k=2;k<n;k*=2),在初学阶段,很难独立查出//每块大小为2,4,8,16...的处理 
        m=k/2;//此处写成 m=n/2;
        for(i=0;i<n;i+=k)//处理完长度为n的序列,每块数据跳跃为k 
            for(j=0;j<m;j++){//每块分半处理,即处理前m个数据,后m个数据
                x=omg[n/k*j]*a[i+j+m];
                a[i+j+m]=a[i+j]-x;//此处写成d[i+j]=a[i+j]-omg[n*j/k]*a[i+j+m];当n=2000000,j=1000000,n*j在int范畴要溢出,真是危机四伏啊
                a[i+j]=a[i+j]+x;//此处写成d[i+j]=a[i+j]+omg[n*j/k]*a[i+j+m];当n=2000000,j=1000000,n*j在int范畴要溢出,真是危机四伏啊 
            } 
    }
}
int main(){
    int lena,lenb,i;
    int x;
    memset(a,0,sizeof(a)),memset(b,0,sizeof(b));
    scanf("%d%d",&lena,&lenb);
    lena+=1,lenb+=1;
    for(i=0;i<lena;i++)scanf("%d",&x),a[i]=x;//此处写成 for(i=0;i<lena;i++)scanf("%lf",&a[i]);
    for(i=0;i<lenb;i++)scanf("%d",&x),b[i]=x;//此处写成 for(i=0;i<lenb;i++)scanf("%lf",&b[i]);
    n=1;
    while(n<lena+lenb)n*=2;
    PI=acos(-1);
    for(i=0;i<n;i++){
        omg[i]=complex<double>(cos(2*PI*i/n),sin(2*PI*i/n));
        inv[i]=complex<double>(cos(2*PI*i/n),-sin(2*PI*i/n));
    }
    FFT(a,omg),FFT(b,omg);//系数化点值
    for(i=0;i<n;i++)a[i]*=b[i];
    FFT(a,inv);//点值化系数
    printf("%d",(int)(a[0].real()/n+0.5));//系数可以大于10.
    for(i=1;i<lena-1+lenb-1+1;i++)printf(" %d",(int)(a[i].real()/n+0.5));
    printf("\n");
    return 0;
}
 

版本3

//P3803 【模板】多项式乘法(FFT)
//在线测评地址https://www.luogu.org/problemnew/show/P3803 
//lena+lenb=2*10^6 2^20=1048576 2^21=2097152 空间需开到2100000 
//C++需用STL中的<complex> 
//才采用 朴素 FFT 递归版本,看几个点会TLE 
//if(n==1)return;//漏了此行,一直没有输出 递归一定要有出口。
//样例通过,提交11分,测试点1,3-8WA,9TLE.2019-2-10 17:03
//重新读题,发现输出一行n+m+1个数字 ,没说什么前导0的问题,看来想多了。
//将处理前导0的功能删除,输出部分,重新编写,提交11分,测试点1,3-9WA。2019-2-10 18:33
//翻看他人代码,发现问题出在输出上,输出未必是 整数啊,输出是浮点数 
//再看看一些代码,发现输出还是整数,只是输出格式做了控制,那么先做输出格式处理 
//提交,老样子,还是11分,2019-2-10 18:58
//将 double x; scanf("%lf",&x),统统改成 int
//提交,老样子,还是11分,2019-2-10 19:01
//n=10^6,n+1=1000001;m=10^6,m+1=1000001,n+1+m+1=2000002,2^21=2097152,最大开到2100000即可 
//随便找了个AC的代码进行提交,开始在提交代码中,找与本人写法类似的代码进行研究 
//以下为11分代码。2019-2-10 20:01 
//找打一个与本人类似的77分代码,进行研究 
//对比了才发现,该题一直在求系数,而非需要进位的乘法,本人一直在求乘法 
//系数可以大于10. 
//修改,提交我的代码终于77分了,提交的结果是88分,测试点9TLE。2019-2-10 20:23 
//好久没这么折腾了,一根筋绕不过来,以下为88分代码。
//朴素FFT算法遇到瓶颈,才有学习优化算法的动力。
//对 << 运算符 不熟悉的 可以 看以下两个例子

1<<0=1
1<<1=2
1<<2=4
1<<3=8
1<<4=16
1<<5=32
1<<6=64
1<<7=128
1<<8=256
1<<9=512
1<<10=1024

0<<1=0
1<<1=2
2<<1=4
3<<1=6
4<<1=8
5<<1=10
6<<1=12
7<<1=14
8<<1=16
9<<1=18
10<<1=20

//对 >> 运算符 不熟悉的 可以 看以下两个例子

0>>1=0
1>>1=0
2>>1=1
3>>1=1
4>>1=2
5>>1=2
6>>1=3
7>>1=3
8>>1=4
9>>1=4
10>>1=5

1>>0=1
1>>1=0
1>>2=0
1>>3=0
1>>4=0
1>>5=0
1>>6=0
1>>7=0
1>>8=0
1>>9=0
1>>10=0

//各位看到没,语言的学习,有人教 固然重要,但更重要的是自身的操练,实践。
//计算机语言的学习,与中文,英文的学习 方法基本类似。
//语言的学习,不是教出来的,而是自己实践出来的。2019-2-11 15:19 

//先写 迭代版 FFT 代码。
//样例未通过,跟踪代码发现if(i<t)swap(&a[i],&a[t]);//此处if一开始写在for(j=0内部,跟踪了程序,才发现写错位置 
//样例未通过,静态排查代码,发现m=k/2;//此处写成 m=n/2; 
//样例未通过,对比https://www.cnblogs.com/RabbitHu/p/FFT.html代码才发现 
//for(k=2;k<=n;k*=2){//此处写成for(k=2;k<n;k*=2),在初学阶段,很难独立查出 
//样例通过,提交44分,测试点5-9WA,什么情况。2019-2-11 22:30
//对比了代码发现,
//d[i+j]=a[i+j]+omg[n/k*j]*a[i+j+m];//此处写成d[i+j]=a[i+j]+omg[n*j/k]*a[i+j+m];当n=2000000,j=1000000,n*j在int范畴要溢出,真是危机四伏啊 
//d[i+j+m]=a[i+j]-omg[n/k*j]*a[i+j+m];//此处写成d[i+j]=a[i+j]-omg[n*j/k]*a[i+j+m];当n=2000000,j=1000000,n*j在int范畴要溢出,真是危机四伏啊 
//乘的时候要特别小心,容易int溢出。
//提交AC。2019-2-11 22:47 
//以下代码为  朴素版 FFT 递归代码 转 迭代版 FFT 代码。可以AC的代码,只是跑得偏慢。  

//脚步不停,继续优化 
//蝴蝶操作,看了https://www.cnblogs.com/RabbitHu/p/FFT.html发现这么简单,但想呢,确很困难。 
//马上修改,提交AC。明显快了很多。2019-2-11 23:02 
//以下为AC代码。 
 
#include <cstdio>
#include <cstring>
#include <complex>
#define maxn 2100000
using namespace std;
complex<double> a[maxn],b[maxn],omg[maxn],inv[maxn];
int c[maxn],n;//n总长度 
double PI;
void swap(complex<double> *a,complex<double> *b){
    complex<double> t;
    t=*a,*a=*b,*b=t;
}
void FFT(complex<double> *a,complex<double> *omg){
    int i,j,k,t,bits=0,m;//bits数据的位数
    complex<double> x;
    while((1<<bits)<n)bits++; 
    for(i=0;i<n;i++){//此处不能改成i<n/2,有反例,n=15,a11与a13互换 
        t=0;
        for(j=0;j<bits;j++)if((i>>j)&1)t|=(1<<(bits-1-j));//t为i的翻转二进制 如i=001,t=100
        if(i<t)swap(&a[i],&a[t]);//此处if一开始写在for(j=0内部,跟踪了程序,才发现写错位置//处理小序号 换 大序号。
    }
    for(k=2;k<=n;k*=2){//此处写成for(k=2;k<n;k*=2),在初学阶段,很难独立查出//每块大小为2,4,8,16...的处理 
        m=k/2;//此处写成 m=n/2;
        for(i=0;i<n;i+=k)//处理完长度为n的序列,每块数据跳跃为k 
            for(j=0;j<m;j++){//每块分半处理,即处理前m个数据,后m个数据
                x=omg[n/k*j]*a[i+j+m];
                a[i+j+m]=a[i+j]-x;//此处写成d[i+j]=a[i+j]-omg[n*j/k]*a[i+j+m];当n=2000000,j=1000000,n*j在int范畴要溢出,真是危机四伏啊
                a[i+j]=a[i+j]+x;//此处写成d[i+j]=a[i+j]+omg[n*j/k]*a[i+j+m];当n=2000000,j=1000000,n*j在int范畴要溢出,真是危机四伏啊 
            } 
    }
}
int main(){
    int lena,lenb,i;
    int x;
    memset(a,0,sizeof(a)),memset(b,0,sizeof(b));
    scanf("%d%d",&lena,&lenb);
    lena+=1,lenb+=1;
    for(i=0;i<lena;i++)scanf("%d",&x),a[i]=x;//此处写成 for(i=0;i<lena;i++)scanf("%lf",&a[i]);
    for(i=0;i<lenb;i++)scanf("%d",&x),b[i]=x;//此处写成 for(i=0;i<lenb;i++)scanf("%lf",&b[i]);
    n=1;
    while(n<lena+lenb)n*=2;
    PI=acos(-1);
    for(i=0;i<n;i++){
        omg[i]=complex<double>(cos(2*PI*i/n),sin(2*PI*i/n));
        inv[i]=complex<double>(cos(2*PI*i/n),-sin(2*PI*i/n));
    }
    FFT(a,omg),FFT(b,omg);//系数化点值
    for(i=0;i<n;i++)a[i]*=b[i];
    FFT(a,inv);//点值化系数
    for(i=0;i<n;i++)c[i]=(int)(a[i].real()/n+0.5);//系数可以大于10. 
    printf("%d",c[0]);
    for(i=1;i<lena-1+lenb-1+1;i++)printf(" %d",c[i]);
    printf("\n");
    return 0;
}


版本2

//P3803 【模板】多项式乘法(FFT)
//在线测评地址https://www.luogu.org/problemnew/show/P3803 
//lena+lenb=2*10^6 2^20=1048576 2^21=2097152 空间需开到2100000 
//C++需用STL中的<complex> 
//才采用 朴素 FFT 递归版本,看几个点会TLE 
//if(n==1)return;//漏了此行,一直没有输出 递归一定要有出口。
//样例通过,提交11分,测试点1,3-8WA,9TLE.2019-2-10 17:03
//重新读题,发现输出一行n+m+1个数字 ,没说什么前导0的问题,看来想多了。
//将处理前导0的功能删除,输出部分,重新编写,提交11分,测试点1,3-9WA。2019-2-10 18:33
//翻看他人代码,发现问题出在输出上,输出未必是 整数啊,输出是浮点数 
//再看看一些代码,发现输出还是整数,只是输出格式做了控制,那么先做输出格式处理 
//提交,老样子,还是11分,2019-2-10 18:58
//将 double x; scanf("%lf",&x),统统改成 int
//提交,老样子,还是11分,2019-2-10 19:01
//n=10^6,n+1=1000001;m=10^6,m+1=1000001,n+1+m+1=2000002,2^21=2097152,最大开到2100000即可 
//随便找了个AC的代码进行提交,开始在提交代码中,找与本人写法类似的代码进行研究 
//以下为11分代码。2019-2-10 20:01 
//找打一个与本人类似的77分代码,进行研究 
//对比了才发现,该题一直在求系数,而非需要进位的乘法,本人一直在求乘法 
//系数可以大于10. 
//修改,提交我的代码终于77分了,提交的结果是88分,测试点9TLE。2019-2-10 20:23 
//好久没这么折腾了,一根筋绕不过来,以下为88分代码。
//朴素FFT算法遇到瓶颈,才有学习优化算法的动力。
//对 << 运算符 不熟悉的 可以 看以下两个例子

1<<0=1
1<<1=2
1<<2=4
1<<3=8
1<<4=16
1<<5=32
1<<6=64
1<<7=128
1<<8=256
1<<9=512
1<<10=1024

0<<1=0
1<<1=2
2<<1=4
3<<1=6
4<<1=8
5<<1=10
6<<1=12
7<<1=14
8<<1=16
9<<1=18
10<<1=20

//对 >> 运算符 不熟悉的 可以 看以下两个例子

0>>1=0
1>>1=0
2>>1=1
3>>1=1
4>>1=2
5>>1=2
6>>1=3
7>>1=3
8>>1=4
9>>1=4
10>>1=5

1>>0=1
1>>1=0
1>>2=0
1>>3=0
1>>4=0
1>>5=0
1>>6=0
1>>7=0
1>>8=0
1>>9=0
1>>10=0

//各位看到没,语言的学习,有人教 固然重要,但更重要的是自身的操练,实践。
//计算机语言的学习,与中文,英文的学习 方法基本类似。
//语言的学习,不是教出来的,而是自己实践出来的。2019-2-11 15:19 

//先写 迭代版 FFT 代码。
//样例未通过,跟踪代码发现if(i<t)swap(&a[i],&a[t]);//此处if一开始写在for(j=0内部,跟踪了程序,才发现写错位置 
//样例未通过,静态排查代码,发现m=k/2;//此处写成 m=n/2; 
//样例未通过,对比https://www.cnblogs.com/RabbitHu/p/FFT.html代码才发现 
//for(k=2;k<=n;k*=2){//此处写成for(k=2;k<n;k*=2),在初学阶段,很难独立查出 
//样例通过,提交44分,测试点5-9WA,什么情况。2019-2-11 22:30
//对比了代码发现,
//d[i+j]=a[i+j]+omg[n/k*j]*a[i+j+m];//此处写成d[i+j]=a[i+j]+omg[n*j/k]*a[i+j+m];当n=2000000,j=1000000,n*j在int范畴要溢出,真是危机四伏啊 
//d[i+j+m]=a[i+j]-omg[n/k*j]*a[i+j+m];//此处写成d[i+j]=a[i+j]-omg[n*j/k]*a[i+j+m];当n=2000000,j=1000000,n*j在int范畴要溢出,真是危机四伏啊 
//乘的时候要特别小心,容易int溢出。
//提交AC。2019-2-11 22:47 
//以下代码为  朴素版 FFT 递归代码 转 迭代版 FFT 代码。可以AC的代码,只是跑得偏慢。  
 
#include <cstdio>
#include <cstring>
#include <complex>
#define maxn 2100000
using namespace std;
complex<double> a[maxn],b[maxn],d[maxn],omg[maxn],inv[maxn];
int c[maxn],n;//n总长度 
double PI;
void swap(complex<double> *a,complex<double> *b){
    complex<double> t;
    t=*a,*a=*b,*b=t;
}
void FFT(complex<double> *a,complex<double> *omg){
    int i,j,k,t,bits=0,m;//bits数据的位数
    while((1<<bits)<n)bits++; 
    for(i=0;i<n;i++){//此处不能改成i<n/2,有反例,n=15,a11与a13互换 
        t=0;
        for(j=0;j<bits;j++)if((i>>j)&1)t|=(1<<(bits-1-j));//t为i的翻转二进制 如i=001,t=100
        if(i<t)swap(&a[i],&a[t]);//此处if一开始写在for(j=0内部,跟踪了程序,才发现写错位置//处理小序号 换 大序号。
    }
    for(k=2;k<=n;k*=2){//此处写成for(k=2;k<n;k*=2),在初学阶段,很难独立查出//每块大小为2,4,8,16...的处理 
        m=k/2;//此处写成 m=n/2;
        for(i=0;i<n;i+=k)//处理完长度为n的序列,每块数据跳跃为k 
            for(j=0;j<m;j++){//每块分半处理,即处理前m个数据,后m个数据
                d[i+j]=a[i+j]+omg[n/k*j]*a[i+j+m];//此处写成d[i+j]=a[i+j]+omg[n*j/k]*a[i+j+m];当n=2000000,j=1000000,n*j在int范畴要溢出,真是危机四伏啊 
                d[i+j+m]=a[i+j]-omg[n/k*j]*a[i+j+m];//此处写成d[i+j]=a[i+j]-omg[n*j/k]*a[i+j+m];当n=2000000,j=1000000,n*j在int范畴要溢出,真是危机四伏啊 
            } 
        for(i=0;i<n;i++)a[i]=d[i];
    }
}
int main(){
    int lena,lenb,i;
    int x;
    memset(a,0,sizeof(a)),memset(b,0,sizeof(b));
    scanf("%d%d",&lena,&lenb);
    lena+=1,lenb+=1;
    for(i=0;i<lena;i++)scanf("%d",&x),a[i]=x;//此处写成 for(i=0;i<lena;i++)scanf("%lf",&a[i]);
    for(i=0;i<lenb;i++)scanf("%d",&x),b[i]=x;//此处写成 for(i=0;i<lenb;i++)scanf("%lf",&b[i]);
    n=1;
    while(n<lena+lenb)n*=2;
    PI=acos(-1);
    for(i=0;i<n;i++){
        omg[i]=complex<double>(cos(2*PI*i/n),sin(2*PI*i/n));
        inv[i]=complex<double>(cos(2*PI*i/n),-sin(2*PI*i/n));
    }
    FFT(a,omg),FFT(b,omg);//系数化点值
    for(i=0;i<n;i++)a[i]*=b[i];
    FFT(a,inv);//点值化系数
    for(i=0;i<n;i++)c[i]=(int)(a[i].real()/n+0.5);//系数可以大于10. 
    printf("%d",c[0]);
    for(i=1;i<lena-1+lenb-1+1;i++)printf(" %d",c[i]);
    printf("\n");
    return 0;
}


版本1

//P3803 【模板】多项式乘法(FFT)
//在线测评地址https://www.luogu.org/problemnew/show/P3803 
//lena+lenb=2*10^6 2^20=1048576 2^21=2097152 空间需开到2100000 
//C++需用STL中的<complex> 
//才采用 朴素 FFT 递归版本,看几个点会TLE 
//if(n==1)return;//漏了此行,一直没有输出 递归一定要有出口。
//样例通过,提交11分,测试点1,3-8WA,9TLE.2019-2-10 17:03
//重新读题,发现输出一行n+m+1个数字 ,没说什么前导0的问题,看来想多了。
//将处理前导0的功能删除,输出部分,重新编写,提交11分,测试点1,3-9WA。2019-2-10 18:33
//翻看他人代码,发现问题出在输出上,输出未必是 整数啊,输出是浮点数 
//再看看一些代码,发现输出还是整数,只是输出格式做了控制,那么先做输出格式处理 
//提交,老样子,还是11分,2019-2-10 18:58
//将 double x; scanf("%lf",&x),统统改成 int
//提交,老样子,还是11分,2019-2-10 19:01
//n=10^6,n+1=1000001;m=10^6,m+1=1000001,n+1+m+1=2000002,2^21=2097152,最大开到2100000即可 
//随便找了个AC的代码进行提交,开始在提交代码中,找与本人写法类似的代码进行研究 
//以下为11分代码。2019-2-10 20:01 
//找打一个与本人类似的77分代码,进行研究 
//对比了才发现,该题一直在求系数,而非需要进位的乘法,本人一直在求乘法 
//系数可以大于10. 
//修改,提交我的代码终于77分了,提交的结果是88分,测试点9TLE。2019-2-10 20:23 
//好久没这么折腾了,一根筋绕不过来,以下为88分代码。 
#include <cstdio>
#include <cstring>
#include <complex>
#define maxn 2100000
using namespace std;
complex<double> a[maxn],b[maxn],d[maxn];
int c[maxn];
double PI;
void FFT(complex<double> *a,int n,int inv){
    int m=n/2,i;
    if(n==1)return;//漏了此行,一直没有输出 递归一定要有出口。 
    complex<double> x;
    for(i=0;i<m;i++)d[i]=a[i*2],d[i+m]=a[i*2+1];//奇偶项分开 
    for(i=0;i<n;i++)a[i]=d[i];
    FFT(a,m,inv),FFT(a+m,m,inv);
    for(i=0;i<m;i++){
        x=complex<double>(cos(2*PI*i/n),inv*sin(2*PI*i/n));
        d[i]=a[i]+x*a[i+m],d[i+m]=a[i]-x*a[i+m];
    }
    for(i=0;i<n;i++)a[i]=d[i];
}
int main(){
    int lena,lenb,i,n;
    int x;
    memset(a,0,sizeof(a)),memset(b,0,sizeof(b)),memset(c,0,sizeof(c));
    scanf("%d%d",&lena,&lenb);
    lena+=1,lenb+=1;
    for(i=0;i<lena;i++)scanf("%d",&x),a[i]=x;//此处写成 for(i=0;i<lena;i++)scanf("%lf",&a[i]);
    for(i=0;i<lenb;i++)scanf("%d",&x),b[i]=x;//此处写成 for(i=0;i<lenb;i++)scanf("%lf",&b[i]);
    n=1;
    while(n<lena+lenb)n*=2;
    PI=acos(-1);
    FFT(a,n,1),FFT(b,n,1);//系数化点值
    for(i=0;i<n;i++)a[i]*=b[i];
    FFT(a,n,-1);//点值化系数
    for(i=0;i<n;i++)c[i]+=(int)(a[i].real()/n+0.5);//系数可以大于10. 
    printf("%d",c[0]);
    for(i=1;i<lena-1+lenb-1+1;i++)printf(" %d",c[i]);
    printf("\n");
    return 0;
}

11分代码

//P3803 【模板】多项式乘法(FFT)
//在线测评地址https://www.luogu.org/problemnew/show/P3803 
//lena+lenb=2*10^6 2^20=1048576 2^21=2097152 空间需开到2100000 
//C++需用STL中的<complex> 
//才采用 朴素 FFT 递归版本,看几个点会TLE 
//if(n==1)return;//漏了此行,一直没有输出 递归一定要有出口。
//样例通过,提交11分,测试点1,3-8WA,9TLE.2019-2-10 17:03
//重新读题,发现输出一行n+m+1个数字 ,没说什么前导0的问题,看来想多了。
//将处理前导0的功能删除,输出部分,重新编写,提交11分,测试点1,3-9WA。2019-2-10 18:33
//翻看他人代码,发现问题出在输出上,输出未必是 整数啊,输出是浮点数 
//再看看一些代码,发现输出还是整数,只是输出格式做了控制,那么先做输出格式处理 
//提交,老样子,还是11分,2019-2-10 18:58
//将 double x; scanf("%lf",&x),统统改成 int
//提交,老样子,还是11分,2019-2-10 19:01
//n=10^6,n+1=1000001;m=10^6,m+1=1000001,n+1+m+1=2000002,2^21=2097152,最大开到2100000即可 
//随便找了个AC的代码进行提交,开始在提交代码中,找与本人写法类似的代码进行研究 
//以下为11分代码。2019-2-10 20:01 
 
#include <cstdio>
#include <cstring>
#include <complex>
#define maxn 2100000
using namespace std;
complex<double> a[maxn],b[maxn],d[maxn];
int c[maxn];
double PI;
void FFT(complex<double> *a,int n,int inv){
    int m=n/2,i;
    if(n==1)return;//漏了此行,一直没有输出 递归一定要有出口。 
    complex<double> x;
    for(i=0;i<m;i++)d[i]=a[i*2],d[i+m]=a[i*2+1];//奇偶项分开 
    for(i=0;i<n;i++)a[i]=d[i];
    FFT(a,m,inv),FFT(a+m,m,inv);
    for(i=0;i<m;i++){
        x=complex<double>(cos(2*PI*i/n),inv*sin(2*PI*i/n));
        d[i]=a[i]+x*a[i+m],d[i+m]=a[i]-x*a[i+m];
    }
    for(i=0;i<n;i++)a[i]=d[i];
}
int main(){
    int lena,lenb,i,n;
    int x;
    memset(a,0,sizeof(a)),memset(b,0,sizeof(b)),memset(c,0,sizeof(c));
    scanf("%d%d",&lena,&lenb);
    lena+=1,lenb+=1;
    for(i=0;i<lena;i++)scanf("%d",&x),a[i]=x;//此处写成 for(i=0;i<lena;i++)scanf("%lf",&a[i]);
    for(i=0;i<lenb;i++)scanf("%d",&x),b[i]=x;//此处写成 for(i=0;i<lenb;i++)scanf("%lf",&b[i]);
    n=1;
    while(n<lena+lenb)n*=2;
    PI=acos(-1);
    FFT(a,n,1),FFT(b,n,1);//系数化点值
    for(i=0;i<n;i++)a[i]*=b[i];
    FFT(a,n,-1);//点值化系数
    for(i=0;i<n;i++){
        c[i]+=(int)(a[i].real()/n+0.5);
        c[i+1]+=c[i]/10;
        c[i]=c[i]%10;
    } 
    printf("%d",c[0]);
    for(i=1;i<lena-1+lenb-1+1;i++)printf(" %d",c[i]);
    printf("\n");
    return 0;
}
 

莫队算法:

18.「czy系列赛」czy的后宫3

spfa:

19.「cf449B」Jzzhu and Cities

数论+快速幂:

20.「fj夏令营」求和

模拟+二分:

21.「fj夏令营」解释器(70分)

dp+期望:

22.「fj夏令营」营销策略

背包dp:

23.「FJ2014集训」简单题(60分)

dfs:

24.「FJ2014集训」简单题(10分)

25.「FJ2014集训」愚蠢的算法(30分)

线段树+计算几何:

26.「FJ2014集训」信心题

上下界网络流:

27.「FJ2014集训」XWW的难题

lca:

28.「FJ2014集训」化合物(70分)

树链剖分+线段树:

29.「FJ2014集训」最短路

splay:

30.「bzoj1251」序列终结者*3 

31.「bzoj3223」JoyOI 1729 文艺平衡树 

32.NOI2005维修数列*2

kruskal:

33.「bzoj1682」Out of Hay 干草危机

状压dp:

34.「bzoj1688」[Usaco2005 Open]Disease Manangement 疾病管理

模拟:

35.「bzoj1637」[Usaco2007 Mar]Balanced Lineup

bfs:

36.「bzoj1615」[Usaco2008 Mar]The Loathesome Hay Baler麻烦的干草打包机

单调栈:

37.「bzoj1628」[Usaco2007 Demo]City skyline

二分+贪心:

38.「bzoj1650」[Usaco2006 Dec]River Hopscotch 跳石子

hall定理+线段树:

39.「FJ2014集训」圆桌会议

博弈论:

40.「cf451A」Game With Sticks

模拟:

41.「cf451B」 Sort the Array

42.「cf451C」Predict Outcome of the Game

乘法逆元+容斥原理+lucas定理:

43.「cf451E」Devu and Flowers

分块:

44.「bzoj2141」排队

dp:

45.「FJ互测」昊昊的机油之GRST(80分)

贪心:

46.「FJ互测」昊昊的机油之GRST

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值