文章目录
今天大佬扔给我一个题单 题目难度递增非常友好(
拿走不谢
然后最近我在做字符串的题就顺着字符串部分做了一些
有字符串哈希和KMP的
字符串哈希只做了一道模板题
KMP做的比较多这里就总结一下咯
哈希就改天吧emmm
P4391 [BOI2009]Radio Transmission 无线传输
题目链接
这道题最简单 循环节长度直接 n - next[n]搞定
AC代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1e6 + 10;
int n;
char s[N];
int ne[N];
void getnext(){
int j = 0,k = -1;
ne[j] = k;
while(j < n){
if(k == -1 || s[j] == s[k]) ne[++ j] = ++ k;
else k = ne[k];
}
}
int main(){
scanf("%d",&n);
scanf("%s",s);
getnext();
printf("%d\n",n - ne[n]);
return 0;
}
P3435 [POI2006]OKR-Periods of Words
题目链接
这道题可以帮助你理解next数组的本质
题目就是要你求每一个前缀的最小的不为零的next
看个图帮助理解
如图我们要让紫色的部分最小化,也就是求最小的next啦
那么如何求最小的next呢
直接next[next[i]]下去就行了,直到next为0就停止,自己想想是为什么呢
AC代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1e6 + 10;
int n;
char s[N];
int ne[N];
long long ans;
void getnext(){
int j = 0,k = -1;
ne[j] = k;
while(j < n){
if(k == -1 || s[j] == s[k]) ne[++ j] = ++ k;
else k = ne[k];
}
}
int main(){
scanf("%d",&n);
scanf("%s",s);
getnext();
for(int i = 2;i <= n;i ++){
int t = i;
while(ne[t]) t = ne[t];
if(ne[i]) ne[i] = t;
ans += i - t;
}
printf("%lld\n",ans);
return 0 ;
}
P4824 [USACO15FEB]Censoring S
题目链接
这是一道匹配并删除子串的问题,也比较经典
之前碰到过但是没了解清楚,现在终于搞清楚了
KMP匹配,再利用一个栈就行了
具体实现看代码:
AC代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1e6 + 10;
int sl,tl;
int ne[N],f[N];
char s[N],t[N];
int stk[N],top;
void getnext(){
for(int i = 2, j = 0;i <= tl;i ++){
while(j && t[i] != t[j + 1]) j = ne[j];
if(t[i] == t[j + 1]) j ++;
ne[i] = j;
}
}
void KMP(){
for(int i = 1,j = 0;i <= sl;i ++){
while(j && s[i] != t[j + 1]) j = ne[j];
if(s[i] == t[j + 1]) j ++;
f[i] = j;
stk[++ top] = i;
if(j == tl) top -= tl,j = f[stk[top]];
}
}
int main(){
scanf("%s%s",s + 1,t + 1);
sl = strlen(s + 1),tl = strlen(t + 1);
getnext();
KMP();
for(int i = 1;i <= top;i++){
printf("%c",s[stk[i]]);
}
return 0;
}
P2375 [NOI2014] 动物园
题目链接
这道题也是利用next数组的本质,只是如果直接暴力递归的话会被卡掉
可以在getnext函数中先预处理出num
然后再进行一次类似的操作判断 j * 2 <= i得出结果
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
const ll mod = 1e9 + 7;
int n,ne[N],num[N];
ll ans;
char s[N];
int main(){
int T;scanf("%d",&T);
while(T --){
scanf("%s",s);
n = strlen(s);
memset(ne,0,sizeof(ne));
int i,j;
j = 0;
num[0] = 0,num[1] = 1;
for( i = 1;i < n;i ++){
while(j && s[i] != s[j]) j =ne[j];
if(s[i] == s[j]) j ++;
ne[i + 1] = j;
num[i + 1] = num[j] + 1;
}
j = 0,ans = 1;
for(i = 1;i < n;i ++){
while(j && s[i] != s[j]) j = ne[j];
if(s[i] == s[j]) j ++;
while((j << 1) > (i + 1)) j = ne[j];
ans = ans * (ll) (num[j] + 1) % mod;
}
printf("%lld\n",ans % mod);
}
return 0;
}
一个小小的总结:
字符串的题变化多端,但总是离不开那几个最本质的东西!祝AC!