阅读理解题
给定文本串的长度 n n n和一个模式串 s s s,并且已知模式串在文本串中某些出现位置(不一定仅在这些位置出现),求可能的文本串的数量。
首先输入有可能出现方案为0的情况(即不合法),于是我们先考虑不合法的判断。
显而易见的是当 s s s出现的结尾位置大于 n n n时,直接可以判定为不合法。
然后就是当两个模式串出现位置有重叠时,假如重叠部分匹配不上,那么显然无解。(具体判定方式下文会将)
如果有解,那么我们只要统计文本串内有多少位置没有被模式串覆盖,记为 c n t cnt cnt,那么答案就是 2 6 c n t 26^{cnt} 26cnt。
具体来考虑如何判断重叠部分是否匹配。显然重叠部分是模式串的一个后缀和前缀的重叠,于是我们只要判断当前位置的后缀和前缀是否匹配。而这个判断可以用两种方式实现: K M P KMP KMP和字符串哈希。
我们发现问题和 K M P KMP KMP算法中的 n e x t next next数组定义类似,于是我们可以想到:以模式串末尾为起始位置,一直跳 n e x t next next指针,途中经过的位置的前缀一定和后缀相等(可以想想 n e x t next next数组的意义)。那么我们只要把这些位置标记出来,只有在这些位置上重叠,前缀和后缀才有可能相等。
涉及到字符串的比较,那么肯定可以想到字符串哈希。我们可以先预处理模式串的哈希值,然后在重叠的时候判断前缀和后缀是否相等即可。
数据有坑,要特判 m = 0 m=0 m=0的情况。
#include
#define ll long long
#define P 1000000007
#define MAX 1000005
using namespace std;
ll qpow(ll a, ll n){
ll res = 1;
while(n){
if(n&1) res = res*a % P;
a = a*a%P;
n >>= 1;
}
return res;
}
char s[MAX];
int n, m, len, Next[MAX], mark[MAX], p[MAX];
void init(){
int j = 0;
len = strlen(s+1);
for(int i = 2; i <= len; i++){
while(j && s[j+1] != s[i]){
j = Next[j];
}
if(s[j+1] == s[i]) j++;
Next[i] = j;
}
for(int i = len; i; i = Next[i]){
mark[i] = 1;
}
}
int main()
{
cin >> n >> m;
scanf("%s", s+1);
init();
for(int i = 1; i <= m; i++){
scanf("%d", &p[i]);
}
if(!m){
cout << qpow(26, n) << endl;
return 0;
}
for(int i = 1; i <= m; i++){
if(p[i]+len-1 > n){
puts("0");
return 0;
}
if(i > 1 && p[i-1]+len > p[i]){
int x = p[i-1]+len-p[i];
if(!mark[x]){
puts("0");
return 0;
}
}
}
int cnt = p[1]-1;
for(int i = 1; i < m; i++){
if(p[i]+len < p[i+1]){
cnt += p[i+1]-p[i]-len;
}
}
cnt += n-p[m]-len+1;
cout << qpow(26, cnt) << endl;
return 0;
}
#include
#define ll long long
#define P 1000000007
#define MAX 1000005
using namespace std;
ll qpow(ll a, ll n){
ll res = 1;
while(n){
if(n&1) res = res*a % P;
a = a*a%P;
n >>= 1;
}
return res;
}
const ll b1 = 99979, b2 = 100007;
const ll p = 1e9+7, q = 1e9+9;
ll p1[MAX], sum1[MAX], p2[MAX], sum2[MAX];
char s[MAX];
int n, m, len, a[MAX];
void init(){
len = strlen(s+1);
p1[0] = 1;
for(int i = 1; i <= len; i++){
p1[i] = p1[i-1]*b1%p;
}
p2[0] = 1;
for(int i = 1; i <= len; i++){
p2[i] = p2[i-1]*b2%q;
}
sum1[0] = 0;
for(int i = 1; i <= len; i++){
sum1[i] = (sum1[i-1]*b1%p+s[i]-'a')%p;
}
sum2[0] = 0;
for(int i = 1; i <= len; i++){
sum2[i] = (sum2[i-1]*b2%q+s[i]-'a')%q;
}
}
int main()
{
cin >> n >> m;
scanf("%s", s+1);
init();
for(int i = 1; i <= m; i++){
scanf("%d", &a[i]);
}
if(!m){
cout << qpow(26, n) << endl;
return 0;
}
for(int i = 1; i <= m; i++){
if(a[i]+len-1 > n){
puts("0");
return 0;
}
if(i > 1 && a[i-1]+len > a[i]){
int x = a[i-1]+len-a[i];
if(sum1[x]!=(sum1[len]%p-sum1[len-x]*p1[x]%p+p)%p || sum2[x]!=(sum2[len]-sum2[len-x]*p2[x]%q+q)%q){
puts("0");
return 0;
}
}
}
int cnt = a[1]-1;
for(int i = 1; i < m; i++){
if(a[i]+len < a[i+1]){
cnt += a[i+1]-a[i]-len;
}
}
cnt += n-a[m]-len+1;
cout << qpow(26, cnt) << endl;
return 0;
}