此为kmp好题
题意:现在已知串p,还知道串s中与p匹配的都有那些位置,问这样的s串共有多少个
思路:这个题就是直接用p把匹配的位置填上就可以了,没有填的位置就是可以变换的,假设有x个位置那么答案就是26^x。需要注意的是重复的地方,如果暴力填的话,复杂度太大,所以可以先求KMP,或者扩展KMP,然后判断重叠的部分会不会有冲突
先把能填的字符都填上,然后通过KMP验证是否符合所有的条件,如果不符合则为0,如果符合则计算26^w,w为s中没有填字符的数量。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int n, m;
char ans[1000100];
int vis[1000100];
char p[1000100];
int pre[1000100];
int l;
int ma[1000100];
int mat[1000100];
int mmin;
/*
bool scan_d(int &num)//输入整型
{
char in; bool IsN = false;
in = getchar();
if (in == EOF) return false;
while (in != '-' && (in<'0' || in>'9')) {
if (in == EOF)
return false;
in = getchar();
}
if (in == '-'){ IsN = true; num = 0; }
else num = in - '0';
while (in = getchar(), in >= '0'&&in <= '9'){
num *= 10, num += in - '0';
}
if (IsN) num = -num;
return true;
}*/
bool cptpf(int prefix[], char p[], int len){
int lolp = 0;
prefix[0] = prefix[1] = 0;
int nocm = 2;
for (nocm = 2; nocm < len + 1; nocm++){
while (lolp>0 && p[lolp] != p[nocm - 1])
lolp = prefix[lolp];
if (p[lolp] == p[nocm - 1])
lolp++;
prefix[nocm] = lolp;
if (vis[nocm+mmin-1]){
if (nocm == l || lolp == l)
;
else if (lolp < l)
return false;
else {
int rt = lolp;
int flag = 0;
while (rt>l){
rt = prefix[rt];
if (vis[rt + mmin - 1]){//没有此处的优化是不能过的,用例41会TLE
flag = 1;
break;
}
}
if (flag);
else if (rt < l)
return false;
}
}
}
return true;
}
int main(){
int i, j;
while (~scanf("%d%d", &n, &m)){
scanf("%s", p);
if (m == 0){
long long w = 1;
for (i = 0; i < n; i++){
w *= 26;
w %= 1000000007;
}
printf("%I64d\n", w);
continue;
}
memset(ans, '0', sizeof(ans));
memset(vis, 0, sizeof(vis));
l = strlen(p);
mmin = 0x3f3f3f3f;
for (i = 1; i <= m; i++){
//scan_d(ma[i]);
scanf("%d", &ma[i]);
if (mmin>ma[i])
mmin = ma[i];
mat[i] = ma[i] + l - 2;
}
//sort(ma + 1, ma + m + 1);
sort(mat + 1, mat + m + 1);
for (i = 1; i <= m; i++){
int tr = mat[i];
while (tr >= mat[i] - l + 1 && ans[tr] == '0'){
ans[tr] = p[tr + l - mat[i] - 1];
tr--;
}
}
for (i = 1; i <= m; i++)
vis[mat[i] + 1] = 1;
int re = cptpf(pre, ans + mmin - 1, n - mmin + 1);
if (re == false){
printf("0\n");
continue;
}
long long w = 1;
for (i = 0; i < n; i++){
if (ans[i] == '0'){
w *= 26;
w %= 1000000007;
}
}
printf("%I64d\n", w);
}
return 0;
}
强行用kmp调了好久才过去
有几个注意点
1、1e9+7这种数以后还是用define 或者const吧,我才不会说,一开始竟然写成了1000000009.。。
2、注意代码中注释的优化
3、TLE了要先看看输入挂是不是能起到效果,不能盲目使用
4、个人感觉这道题如果用EKMP会好一点吧,不过EKMP学的不怎么滴,学完来加EKMP代码