题目链接:点击打开链接
题意:
用小写字母构造n长的串S,m个要求
字符串P
下面m个位置。a1, a2···am(输入有序)
要使得字符串S的以ai 开头且后面是一个P串。
问构造的方法数
思路:
实际上,对于ai, ai+1 ,两个位置,如果这两个位置会相互影响(即 ai+1 - ai < len)
复制一个和P一样的串P‘
把P放在ai位置,把P‘放在ai+1位置,那么只需要判断一下 P的后半段是否和P‘的前半段匹配即可。
也就是P’的哪些位置是和P的尾部相同的。
KMP求出这些位置放到set里。
然后就是简单的判断了
#include <stdio.h>
#include <string.h>
#include <string>
#include <math.h>
#include <map>
#include <vector>
#include <set>
#include <algorithm>
#include <iostream>
using namespace std;
template <class T>
inline bool rd(T &ret) {
char c; int sgn;
if (c = getchar(), c == EOF) return 0;
while (c != '-' && (c<'0' || c>'9')) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
template <class T>
inline void pt(T x) {
if (x <0) {
putchar('-');
x = -x;
}
if (x>9) pt(x / 10);
putchar(x % 10 + '0');
}
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
int f2[N], len;
char s1[N], s2[N];
void getFail(int *f, char *P){
f[0] = f[1] = 0;
for (int i = 1; i < len; i++){
int j = f[i];
while (j&&P[i] != P[j])j = f[j];
f[i + 1] = P[i] == P[j] ? j + 1 : 0;
}
}
set<int>s;
void KMP(int *f, char *S1, char *S2){
getFail(f, S2);
int j = 0, i = 0;
while (i <= len)
{
while (j && S1[i] != S2[j]) j = f[j];
i++, j++;
}
for (int i = len; f[i]; i = f[i])
s.insert(len-f[i]);
}
int m, n;
bool v[N];
int main() {
while (cin >> n){
rd(m);
scanf("%s", s1);
while (m--){
int u; rd(u);
v[u] = true;
}
len = strlen(s1);
memcpy(s2, s1, sizeof s1);
KMP(f2, s1, s2);
ll ans = 1;
for (int i = 1, last = -1e7; i <= n; i++){
if (v[i] == false && i - last >= len){
ans *= 26LL;
if (ans >= mod)ans %= mod;
}
else if (v[i] == true){
if (i - last < len && !s.count(i-last)){
ans = 0; break;
}
last = i;
}
}
pt(ans%mod); puts("");
}
return 0;
}