\(C_n^m\)的typora,点了一下启用源代码模式
就把我已经写好的博客弄没了,就给我留个标题,自动保存也只给我保存了个标题……\(C_n^m\),wdnmd数组
Time limit
1000 msspa
Memory limit
262144 kB.net
打比赛的时候愣是想不到怎么用KMP,总想着若是用kmp,那么每次合并都要更新nxt数组,会被卡到n方,就是想不到老字符串不用每次都全体参与KMP,每次只须要把老字符串后面那段拿出来判断就好了……还想着是否是要用啥我如今还不会的高级玩意……对KMP的理解只停留在作最裸的那种板题……指针
KMP有两种玩法,目的都是在合并老字符串(以前合并的结果)和新字符串(最新读入的)的时候找出能够被合并的长度,而后就能把新字符串后面那截不能合并的接到老字符串后面。边写边骂typora。因为合并的时候,老字符串和新字符串重复的长度小于等于新字符串的长度,因此处理的时候都截取老字符串后面和新字符串等长的一截(若是新字符串比老字符串长,那么就选整个老字符串)code
一种是官方题解的思路——先把新字符串放前面,把“老字符串的后面一截”放后面,而后对于这个新接的合体字符串跑一遍KMP,求出nxt数组,以便找到最长的border(这个是nxt数组的定义了),这个就是能够合并的长度了,固然这个值要是大于了读入的新字符串或者以前合并出来的老字符串的长度,就要取“最长border长度、读入的新字符串的长度、以前合并的老字符串的长度”这三者的最小值,由于合并两个字符串最多就是一个把另外一个吞并了,长度不会小于两个字符串中的任意一个。blog
另外一种思路来自这篇博客——每次读入新字符串之后,把新字符串做为模式串,把老字符串的后面那截做为文本串。而后就跑几乎是裸的KMP了——先求出新字符串的nxt数组,而后用新字符串去匹配文本串(老字符串的后面那截),若是匹配的时候文本串的指针跑到头了,那么如今这个模式串指针指向的字符就是合并后新字符串贡献的第一个字符。若是文本串指针还没跑到头,模式串指针跑到头了,那么说明新字符串合并上去之后就啥都不剩了,彻底被老字符串吞并了。这两种状况,均可以返回模式串指针的位置。这个位置一直到新字符串末尾这段就是要新加的了。ip
另外,KMP各类写法致使的指针加一减一的问题,微调一下就行了。字符串
快速求几个子串的哈希值的方法,貌似NOI201六、2017连着考了两年,其余时候也用得很多,但我至今还没填坑……再次留坑。扔个连接先跑了。get
#include<cstdio> #include<cstring> #include<algorithm> const int MAXN=1e6+5; int n; char a[MAXN],b[MAXN]; int nxt[MAXN]; int lena,lenb; int kmp(int st)//传入模式串的匹配起点 { int i,j; nxt[0]=-1; for(i=1,j=-1;i<lenb;i++) { while(~j&&b[i]!=b[j+1]) j=nxt[j]; if(b[i]==b[j+1]) j++; nxt[i]=j; } // for(int x=0;x<lenb;x++) printf("%d ",nxt[x]); // puts(b); for(i=st,j=-1;i<lena;i++) { while(~j&&b[j+1]!=a[i]) j=nxt[j]; if(a[i]==b[j+1]) j++; if(j==lenb-1) return lenb; } return j+1; } int main() { //freopen("test.in","r",stdin); scanf("%d%s",&n,a); lena=strlen(a); n--; while(n--) { scanf("%s",b); lenb=strlen(b); int temp=kmp(std::max(0,lena-lenb)); // printf("%d\n",temp); for(int i=temp;i<lenb;i++) a[lena++]=b[i]; } a[lena]=0; puts(a); return 0; }
这场CF的F题据说是什么基环树,太难了(借口),留坑,不补了iframe