题解 AtCoder-4414 Prefix Suffix Free

本文详细解析AtCoder-4414 PrefixSuffixFree问题,通过KMP算法中的next数组高效解决字符串匹配难题,避免重复计算,实现快速求解。

题解 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。
真的感觉自己菜爆了,以后的几天会更加努力的

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值