总目录详见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