此爲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代碼