题意:
给 定 模 式 串 s t r , 以 及 m 个 位 置 p o s [ i ] , 1 < = i < = m , 要 求 从 位 置 p o s [ i ] 开 始 的 后 缀 子 串 的 前 缀 要 包 含 s t r , 求 满 足 条 件 的 , 长 度 为 n 的 字 符 串 共 有 多 少 种 可 能 。 给定模式串str,以及m个位置pos[i],1<=i<=m,要求从位置pos[i]开始的后缀子串的前缀要包含str,\\求满足条件的,长度为n的字符串共有多少种可能。 给定模式串str,以及m个位置pos[i],1<=i<=m,要求从位置pos[i]开始的后缀子串的前缀要包含str,求满足条件的,长度为n的字符串共有多少种可能。
输入输出:
Input:
The first line contains two integers n and m, the length of s and the length of the subsequence Malekas wrote down (1 ≤ n ≤ 106 and 0 ≤ m ≤ n - |p| + 1).
The second line contains string p (1 ≤ |p| ≤ n).
The next line contains m space separated integers y1, y2, …, ym, Malekas’ subsequence (1 ≤ y1 < y2 < … < ym ≤ n - |p| + 1).
Output:
In a single line print the answer modulo 1000 000 007.
Sample Input:
6 2
ioi
1 3
Sample Output:
26
Sample Input:
5 2
ioi
1 2
Sample Output:
0
Note:
In the first sample test all strings of form “ioioi?” where the question mark replaces arbitrary English letter satisfy.
Here |x| denotes the length of string x.
Please note that it’s possible that there is no such string (answer is 0).
EG:
样 例 1 : 给 定 母 串 长 度 n = 6 , 模 式 串 长 度 m = 3 , 模 式 串 为 i o i , 要 求 从 1 , 3 位 置 开 始 的 后 缀 子 串 的 前 缀 为 i o i , 可 以 确 定 长 度 为 6 的 母 串 的 前 5 位 字 符 为 i o i o i _ , 第 六 位 可 填 任 意 字 母 , 因 此 满 足 题 意 的 数 量 为 2 6 1 = 26 。 样例1:给定母串长度n=6,模式串长度m=3,模式串为ioi,要求从1,3位置开始的后缀子串的前缀为ioi,\\可以确定长度为6的母串的前5位字符为ioioi\_,第六位可填任意字母,因此满足题意的数量为26^1=26。 样例1:给定母串长度n=6,模式串长度m=3,模式串为ioi,要求从1,3位置开始的后缀子串的前缀为ioi,可以确定长度为6的母串的前5位字符为ioioi_,第六位可填任意字母,因此满足题意的数量为261=26。
题解:
一 开 始 的 想 法 是 先 计 算 相 邻 位 置 p o s [ i + 1 ] 与 p o s [ i ] 之 差 , 若 差 小 于 模 式 串 长 度 l e n − 1 就 无 法 满 足 条 件 , 若 恰 好 等 于 l e n − 1 , 还 需 要 判 断 模 式 串 的 第 一 个 字 符 和 最 后 一 个 字 符 是 否 相 同 , 如 样 例 2 。 一开始的想法是先计算相邻位置pos[i+1]与pos[i]之差,若差小于模式串长度len-1就无法满足条件,\\若恰好等于len-1,还需要判断模式串的第一个字符和最后一个字符是否相同,如样例2。 一开始的想法是先计算相邻位置pos[i+1]与pos[i]之差,若差小于模式串长度len−1就无法满足条件,若恰好等于len−1,还需要判断模式串的第一个字符和最后一个字符是否相同,如样例2。
现 在 发 现 了 思 考 的 漏 洞 : 现在发现了思考的漏洞: 现在发现了思考的漏洞:
如 : 模 式 串 a b a b , 长 度 l e n = 4 , 若 两 个 相 邻 位 置 间 隔 为 1 , 1 < 4 − 1 = 3 , 却 仍 然 可 以 满 足 题 意 。 如:模式串abab,长度len=4,若两个相邻位置间隔为1,1<4-1=3,却仍然可以满足题意。 如:模式串abab,长度len=4,若两个相邻位置间隔为1,1<4−1=3,却仍然可以满足题意。
所以,判断的依据应当是模式串最长相同前后缀的长度!
接 下 来 需 要 统 计 相 邻 位 置 之 间 “ 可 以 填 任 意 字 母 ” 的 位 置 的 个 数 , 也 不 要 忘 了 最 后 要 判 断 总 长 度 是 否 超 过 n 。 求 出 总 的 “ 空 位 ” 个 数 c n t , 再 计 算 2 6 c n t 即 最 终 方 案 总 数 。 接下来需要统计相邻位置之间“可以填任意字母”的位置的个数,也不要忘了最后要判断总长度是否超过n。\\求出总的“空位”个数cnt,再计算26^{cnt}即最终方案总数。 接下来需要统计相邻位置之间“可以填任意字母”的位置的个数,也不要忘了最后要判断总长度是否超过n。求出总的“空位”个数cnt,再计算26cnt即最终方案总数。
用 到 最 长 相 同 前 后 缀 的 长 度 , 想 到 K M P 算 法 中 的 N e x t 数 组 。 用到最长相同前后缀的长度,想到KMP算法中的Next数组。 用到最长相同前后缀的长度,想到KMP算法中的Next数组。
N e x t [ i ] : 前 i 个 字 符 中 , 前 缀 与 后 缀 相 同 部 分 最 长 的 长 度 。 Next[i]:前i个字符中,前缀与后缀相同部分最长的长度。 Next[i]:前i个字符中,前缀与后缀相同部分最长的长度。
所 以 我 们 对 模 式 串 求 N e x t 数 组 后 , 利 用 N e x t 数 组 从 模 式 串 末 尾 开 始 , 递 归 标 记 每 一 个 循 环 节 的 前 一 个 循 环 节 的 一 端 。 所以我们对模式串求Next数组后,利用Next数组从模式串末尾开始,递归标记每一个循环节的前一个循环节的一端。 所以我们对模式串求Next数组后,利用Next数组从模式串末尾开始,递归标记每一个循环节的前一个循环节的一端。
如 : 对 模 式 串 a b a b , i : 1 2 3 4 N e x t [ i ] : 0 0 1 2 , 我 们 把 从 末 尾 4 开 始 标 记 , 接 着 N e x t [ 4 ] = 2 , 再 把 2 标 记 。 若 模 式 串 长 度 减 去 相 邻 位 置 的 间 隔 恰 好 被 标 记 过 , 即 l e n − ( p o s [ i + 1 ] − p o s [ i ] ) 在 模 式 串 中 的 位 置 恰 好 是 前 一 个 循 环 节 的 一 端 , 说 明 可 行 。 反 应 到 上 图 就 是 4 − 2 = 2 , 恰 好 是 后 一 个 循 环 节 a b 的 前 一 个 循 环 节 a b 的 后 端 所 在 的 位 置 。 如:对模式串abab,\\ \qquad \quad i: 1\ \ 2\ \ 3\ \ 4\\Next[i]: \ 0\ \ 0\ \ 1\ \ 2,\\我们把从末尾4开始标记,接着Next[4]=2,再把2标记。\\若模式串长度减去相邻位置的间隔恰好被标记过,\\即len-(pos[i+1]-pos[i])在模式串中的位置恰好是前一个循环节的一端,说明可行。\\反应到上图就是4-2=2,恰好是后一个循环节ab的前一个循环节ab的后端所在的位置。 如:对模式串abab,i:1 2 3 4Next[i]: 0 0 1 2,我们把从末尾4开始标记,接着Next[4]=2,再把2标记。若模式串长度减去相邻位置的间隔恰好被标记过,即len−(pos[i+1]−pos[i])在模式串中的位置恰好是前一个循环节的一端,说明可行。反应到上图就是4−2=2,恰好是后一个循环节ab的前一个循环节ab的后端所在的位置。
具体落实:
① 、 利 用 K M P 中 的 N e x t 数 组 来 判 断 , 从 最 后 一 个 循 环 节 向 前 标 记 每 一 个 循 环 节 的 末 端 。 ①、利用KMP中的Next数组来判断,从最后一个循环节向前标记每一个循环节的末端。 ①、利用KMP中的Next数组来判断,从最后一个循环节向前标记每一个循环节的末端。
② 、 计 算 相 邻 位 置 的 间 隔 , 若 间 隔 长 度 小 于 模 式 串 的 长 度 − 1 , 则 需 要 判 断 是 否 处 在 某 循 环 节 的 末 端 位 置 。 ③ 、 计 算 所 有 “ 空 位 ” 的 数 量 c n t , 总 的 方 案 数 即 2 6 c n t 。 ②、计算相邻位置的间隔,若间隔长度小于模式串的长度-1,则需要判断是否处在某循环节的末端位置。\\③、计算所有“空位”的数量cnt,总的方案数即26^{cnt}。 ②、计算相邻位置的间隔,若间隔长度小于模式串的长度−1,则需要判断是否处在某循环节的末端位置。③、计算所有“空位”的数量cnt,总的方案数即26cnt。
注意:
① 、 m = 0 的 情 况 不 能 漏 了 特 判 。 ② 、 最 后 一 个 位 置 的 模 式 串 可 能 会 超 过 长 度 n 。 ③ 、 第 一 个 位 置 未 必 是 1 , 因 此 第 一 个 位 置 之 前 仍 然 可 能 存 在 “ 空 位 ” 。 ①、m=0的情况不能漏了特判。\\②、最后一个位置的模式串可能会超过长度n。\\③、第一个位置未必是1,因此第一个位置之前仍然可能存在“空位”。 ①、m=0的情况不能漏了特判。②、最后一个位置的模式串可能会超过长度n。③、第一个位置未必是1,因此第一个位置之前仍然可能存在“空位”。
代码:
#include
#include
#include
#include
#include
#define ll long long
#define inf 0x7fffffff
using namespace std;
const int mod=1e9+7;
const int N=1e6+10;
int n,m,len; ///len为模式串的长度
char s[N];
int pos[N],Next[N];
bool mark[N]; ///标记
void get_next()
{
for(int i=2,j=0;i<=len;i++)
{
while(j&&s[i]!=s[j+1]) j=Next[j];
if(s[i]==s[j+1]) j++;
Next[i]=j;
}
}
ll quick_pow(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1) ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return ans%mod;
}
int main()
{
cin>>n>>m;
scanf("%s",s+1);
if(!m) {
printf("%lld\n",quick_pow(26,n));return 0;} ///不能忘了特判m=0
len=strlen(s+1);
get_next();
for(int i=len;i;i=Next[i]) mark[i]=true;
for(int i=1;i<=m;i++)
{
scanf("%d",&pos[i]);
if(i!=1&&pos[i]-pos[i-1]<len) ///相邻位置间隔小于模式串长度的情况,需要判断是否被Next数组标记过
{
if(!mark[ pos[i-1]+len-pos[i] ])
{
cout<<0<<endl;
return 0;
}
}
}
if(n-pos[m]<len-1) cout<<0<<endl; ///判断最后一个位置是否会超过长度n
else ///统计空位的数量
{
int cnt=pos[1]-1; ///第一个位置前的数字也是任意的
for(int i=2;i<=m;i++)
if(pos[i]-pos[i-1]>len)
cnt+=pos[i]-pos[i-1]-len;
cnt+=n-pos[m]-len+1; ///加上最后一个位置到末尾的空位
printf("%lld\n",quick_pow(26,cnt));
}
return 0;
}