P9523

先 orz oyds。但是为什么没有 oyds 的简单预处理做法啊。

区间 dp。dpi,j 表示凑出区间 [i,j] 的最小代价。考虑枚举当前区间 [i,j]k,表示 [i,j] 在区间 [p,j] 中出现了 k 次,且 p 取得最大值。则有转移:

min(dpp,j,dpi,j+B+k×C+(jp+1k×len)×A)dpp,j

以及最基本的:

min(dpi+1,j,dpi,j1,dpi,j)dpi,j

这部分复杂度为 O(nni)=O(n2lnn)

现在就要考虑怎么找这个 k 对应的 p。考虑维护 S 每两个后缀的 lcp。简单 dp 即可。然后维护对于一对 (i,k)minj 使得 lcp(S[i:n],S[j:n])k。这个东西可以先记录 =k 的情况,然后求后缀最大值。

这部分 O(n2)

简单好写。

code:

点击查看代码
int n,m,lcp[N][N],pre[N][N];
ll A,B,C,dp[N][N];
char s[N];
void Yorushika(){
	scanf("%d%s%lld%lld%lld",&n,s+1,&A,&B,&C);
	drep(i,n,1){
		drep(j,i-1,1){
			lcp[i][j]=s[i]==s[j]?lcp[i+1][j+1]+1:0;
			lcp[i][j]=min(lcp[i][j],i-j);
			if(!pre[i][lcp[i][j]])
				pre[i][lcp[i][j]]=j;
		}
		drep(j,n,1){
			pre[i][j]=max(pre[i][j],pre[i][j+1]);
		}
	}
	mems(dp,0x3f);
	rep(i,1,n){dp[i][i]=A;}
	rep(len,1,n){
		rep(i,1,n-len+1){
			int j=i+len-1;
			dp[i][j]=min({dp[i][j],dp[i+1][j]+A,dp[i][j-1]+A});
			int p=i;
			rep(k,1,j/len){
				p=pre[p][len];
				if(!p)break;
				dp[p][j]=min(dp[p][j],dp[i][j]+B+(k+1)*C+(j-p+1-(k+1)*len)*A);
			}
		}
	}
	printf("%lld\n",dp[1][n]);
}
signed main(){
	int t=1;
	//	scanf("%d",&t);
	while(t--)
		Yorushika();
}
posted @   yinhee  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!

阅读目录(Content)

此页目录为空

点击右上角即可分享
微信分享提示