HDU - 6583

题目链接:HDU - 6583


显然可以dp, dp[i] 为以 i 结尾的最小花费。
dp[i]=min(dp[i-1]+p,dp[j]+q)保证 str(j+1,i)str(1,j) 的子串即可。
显然这个花费是单调递增的。由子串的性质可以证明。
所以我们枚举的时候,可以用 尺取 + SAM 求出可以转移的最远的 j 。

AC代码:

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include
//#define int long long
using namespace std;
const int N=4e5+10;
char str[N]; int n,p,q,now,pos; long long dp[N];
struct SAM{
	int cnt=1,last=1,sz[N];
	struct node{int ch[26],len,fa;}d[N];
	inline void init(){
		for(int i=1;i<=cnt;i++) d[i].fa=d[i].len=0,memset(d[i].ch,0,sizeof d[i].ch);
		cnt=last=1;
	}
	inline void insert(int c){
		int p=last,np=last=++cnt;	sz[cnt]=1;
		d[np].len=d[p].len+1;
		for(;p&&!d[p].ch[c];p=d[p].fa)	d[p].ch[c]=np;
		if(!p)	d[np].fa=1;
		else{
			int q=d[p].ch[c];
			if(d[q].len==d[p].len+1)	d[np].fa=q;
			else{
				int nq=++cnt;
				d[nq]=d[q],d[nq].len=d[p].len+1,d[q].fa=d[np].fa=nq;
				for(;p&&d[p].ch[c]==q;p=d[p].fa) d[p].ch[c]=nq;
			}
		}
	}
}sam;
inline void solve(){
	now=1,pos=1; n=strlen(str+1); sam.init();
	for(int i=1,k;i<=n;i++){
		dp[i]=dp[i-1]+p;	k=str[i]-'a';
		while((!sam.d[now].ch[k]||i-pos+1>pos-1)&&pos<=i){
			sam.insert(str[pos++]-'a');
			while(now&&sam.d[sam.d[now].fa].len>=i-pos)	now=sam.d[now].fa;
			if(!now)	now=1;
		}
		now=sam.d[now].ch[k];
		while(now&&sam.d[sam.d[now].fa].len>=i-pos+1)	now=sam.d[now].fa;
		if(!now)	now=1;
		if(pos<=i)	dp[i]=min(dp[i],dp[pos-1]+q);
	}
	printf("%lld\n",dp[n]);
}
signed main(){
	while(~scanf("%s %d %d",str+1,&p,&q))	solve();
	return 0;
}

你可能感兴趣的:(HDU,SAM,动态规划)