bzoj3620

题面

题目

“Madoka,不要相信 QB!”伴随着 Homura 的失望地喊叫,Madoka 与 QB 签订了契约. 这是 Modoka 的一个噩梦,也同时是上个轮回中所发生的事.为了使这一次 Madoka 不再与 QB签订契约,Homura 决定在刚到学校的第一天就解决 QB.然而,QB 也是有许多替身的(但在第八话中的剧情显示它也有可能是无限重生的),不过,意志坚定的 Homura 是不会放弃的——她决定 消灭所有可能是 QB 的东西.现在,她已感受到附近的状态,并且把它转化为一个长度为 n 的字符串交给了学 OI 的你. 现在你从她的话中知道 , 所有形似于 A+B+A 的字串都是 QB 或它的替身 , 且len(A)>=k,len(B)>=1 (位置不同其他性质相同的子串算不同子串,位置相同但拆分不同的子串算同一子串),然后你必须尽快告诉 Homura 这个答案——QB 以及它的替身的数量.

输入输出格式

输入格式

第一行一个字符串,第二行一个数 k

输出格式

仅一行一个数 ans,表示 QB 以及它的替身的数量

样例

样例输入1

aaaaa
1

样例输出1

6

样例输入2

abcabcabc
2

样例输出2

8

解答

其实还是比较裸的kmp的题。主要是理解清楚kmp的fail的含义当前失配以后去哪里 通过这个含义,我们可以想到用它来解决A+B+A的问题。若对于后面的串A,我们发现其实对于A[1]要找到它在前面的A中的对应位置只需要求得fail[i]就行了 对于当前的j来说,只要j!=pos(pos是枚举的开始位置)并且(j-pos+1)2>=i-pos+1,就是说明两个A串的长度加起来都大于等于(取等是因为len(B)>=1目前枚举到的pos-i串的长度了,肯定不可能构成一个A+B+A型的串,所以要把j向前调整,就是向前跳。最后判断一下如果(j-pos+1)2>=k,就说明这里找到匹配了,计数加一个。因为这道题说的是只要位置不同就行,即只要对于每一个pos,只要符合条件的j取到的时候,i与之前不同,就不同。所以这里直接ans++一下就行。快写有问题,输出是一样的,但是交上去却死活过不了 以下是代码

# include <cstdio>
# include <cstdlib>
# include <time.h>
# include <vector>
# include <cstring>
using namespace std;
int read(){
	int x = 0,f = 1;
	static char c = getchar();
	while(c<'0'||c>'9'){if(c=='-') f = -1;c = getchar();}
	while(c>='0'&&c<='9')x = x*10+c-'0',c = getchar();
	return x*f;
}
const int MAXN = 15010;
int nxt[MAXN];
char str[MAXN];
int n,k;
int ans = 0;
void kmp(int pos){
	int j = 0;
	nxt[pos] = pos-1;
	for(int i = pos+1;i<=n;i++){
		j = nxt[i-1];
		while(j!=pos-1&&str[i]!=str[j+1]) j = nxt[j];
		if(str[i] == str[j+1])j++;
		nxt[i] = j;
	}
	j = nxt[pos];
	for(int i = pos+1;i<=n;i++){
		while(j!=pos-1&&str[i]!=str[j+1])j = nxt[j];
		if(str[i]==str[j+1])j++;
		while((j-pos+1)*2>=(i-pos+1))
			j = nxt[j];
		if((j-pos+1)>=k)
			ans++;
	}
}
int main(void){
	scanf("%s",str+1);
	k = read();
	n = strlen(str+1);
	for(int i = 1;i<=n;i++)kmp(i);//枚举以i作为开头
	printf("%d",ans);
	return 0;
}