题目链接:点击打开链接
题意:
用小写字母构造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; }
时间: 2024-10-05 05:05:00