AtCoder Beginner Contest 257 G - Prefix Concatenation(KMP)

题目链接:G - Prefix Concatenation

考虑dp,设f[i]表示至少要用f[i]个s前缀拼出t的前i个字符,容易发现dp值是单调不减的,所以有一种最优的策略:考虑拼出t的前i个字符时,最优的策略就是让本次选的前缀最长。

所以,我们可以考虑kmp,把s+#+t拼成一个新的字符串,求它的next数组,这样就可以O(1)地知道t的每个位置能选的最长前缀长度。然后就能O(n)地dp了。

为什么要加这个#呢?是为了让t这一部分的ne值无法超过s的长度,这样就只能让t和s匹配,而不会出现t和t自身匹配的错误情况。

完整代码:

#include <bits/stdc++.h>
using namespace std;
#define FOR(i,a,b) for(int i=(a), (i##i)=(b); i<=(i##i); ++i)
#define ROF(i,a,b) for(int i=(a), (i##i)=(b); i>=(i##i); --i)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
#define int long long
const int N = 5e5+5, inf=1e18;
char s[N],t[N],ss[N];
int n,m,f[N]; //f[i]表示至少要用f[i]个s前缀拼出t的前i个字符
int ne[N<<1]; //ss的next数组

signed main(){
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	cin>>(s+1)>>(t+1);
	n=strlen(s+1), m=strlen(t+1);
	FOR(i,1,n) ss[i]=s[i]; ss[n+1]='#'; //分隔标记,防止s和t匹配混乱
	FOR(j,1,m) ss[j+n+1]=t[j]; ss[n+m+2]='\0';

	//构建ss串的next数组
	for(int i=2, j=0; i<=n+m+1; i++){
		while(j && ss[i]!=ss[j+1]) j=ne[j];
		if(ss[i]==ss[j+1]) j++;
		ne[i] = j;
	}

	FOR(i,1,m) f[i]=inf;
	FOR(i,1,m){
		cmin(f[i], f[i-ne[i+n+1]]+1);
	}
	if(f[m]==inf) cout<<-1;
	else cout<<f[m];
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值