题解 AtCoder-4414 Prefix Suffix Free
Date 2019.7.31
题目大意
读入一个字符串S。统计满足条件的字符串T的个数。条件有以下两条:
1.T和S长度相等
2.对于S的一个长度为K的前缀,它不能是T的后缀
答案对1e9+7取模
思路
首先,思考如何去写暴力。
很显然暴力的做法是枚举S的所有前缀,并去除其中被包含的那些,再利用组合数学求得不合法的个数,并用总个数一减,就是答案。
那么什么算是被包含了呢?举个简单的例子,S=abcab。它的前缀中有两个分别为a和abca。根据条件2,T的一个后缀不能为S的前缀,即T的最后一位不为a,那么也就自然满足了T的后缀不为abca。
总结一下就是:如果S的一个前缀是S的另一个前缀的后缀,那么这个长度较大的S的前缀对答案就没有贡献。
但是如果暴力地使用KMP依次比较S的前缀,这显然是会TLE的。
其实,此时的我们已经离正解不远了。
我们想要做的就是判断出S的某个子串里的后缀是否等于这个子串中的前缀。仔细想想,KMP中的next数组就可以达到我们的目的啊!
那么思路就很清晰了:在S上跑一遍KMP中的getnext()函数(不同的KMP写法函数名可能不相同)。如果next[i]为0,我们才计算出其对答案的贡献。
下面附上本人的代码
#include<iostream>
#include<cstdio>
#include<cstring>
#define mo 1000000007
#define maxn 1000009
using namespace std;
int Next[maxn];
char c[maxn];
long long KSM (int x)
{
long long k=1,a=26;
for (;x;x>>=1,a=(a*a)%mo)
if (x&1)
k=(k*a)%mo;
return k;
}
void getnext(char *ptr)
{
int i,n,k;
n=strlen(ptr);
k=-1;
Next[0]=-1;
i=0;
while(i<n)
{
if(k==-1 || ptr[i]==ptr[k])
{
i++;
k++;
Next[i]=k;
}
else k=Next[k];
}
}
int main ()
{
scanf("%s",c);
int l=strlen(c);
getnext(c);//求出Next数组的值
long long ans=KSM(l);//求出所有的方案数
for (int i=1;i<=l;i++)
{
if (Next[i])//如果Next[i]==1,说明前面有更小的前缀是当前前缀的后缀,便直接跳过
continue;
ans=(ans+mo-KSM(l-i))%mo;//用总方案数减去当前前缀对应的不合法的方案数
}
cout<<ans<<endl;
return 0;
}
尾记
这两天一直想做几道洛谷的紫题,但却一直没有a掉。今天是第一场acm赛,我的队友考场15分钟不到就a了这道题,我却花了两个多小时。
好吧,其中的两个小时用来挑错误,结果最后的错误居然是把本应为1e9+7的mod写成了1e9+9 QAQ。
真的感觉自己菜爆了,以后的几天会更加努力的
本文详细解析AtCoder-4414 PrefixSuffixFree问题,通过KMP算法中的next数组高效解决字符串匹配难题,避免重复计算,实现快速求解。
1697

被折叠的 条评论
为什么被折叠?



