SP15736 BRKSTRNG - Breaking String

传送门

题目思路

这里学习完后跑来做这道题,这解释了为什么我能想到拆分转化成合并。不知道 Knuth 的先去学习一下叭。

比较板的题,动态规划部分就不讲了,主要解释一下怎么计算代价。

定义 \(a_i\) 为第 \(i\) 段的末尾。那么易得第 \(i\) 段的范围就是 \(a_{i-1}+1\)\(a_i\)。不要忘记 \(n\) 也是一个结尾。

\(i\)\(j\) 中所有段合并时,代价就是 \(a_j-(a_{i-1}+1)+1=a_j-a_{i-1}\)

剩下的就很简单了。代码中还有注释。

AC Code

#include<bits/stdc++.h>
using namespace std;
const int N=1e7+5,M=1005;
int n,m,a[M],f[M][M],opt[M][M];
int w(int i,int j){
	return a[j]-a[i-1];//即a[j]-(a[i-1]+1)+1
}
void solve(){
	for(int i=1;i<=m;i++)	cin>>a[i];//第i段:a[i-1]+1~a[i] 
	a[m+1]=n;//字符串最后一个末尾 
	//a[0]=0
	for(int i=1;i<=m+1;i++){
		f[i][i]=0;
		opt[i][i]=i;//决策点 
	}
	for(int len=2;len<=m+1;len++){//应该解释为段的数量 
		for(int i=1,j=len;j<=m+1;i++,j++){
			f[i][j]=1e9;
			for(int k=opt[i][j-1];k<=opt[i+1][j];k++){
				if(f[i][j]>f[i][k]+f[k+1][j]+w(i,j)){
					f[i][j]=f[i][k]+f[k+1][j]+w(i,j);
					opt[i][j]=k;
				}
			}
		}
	}
	cout<<f[1][m+1]<<"\n";
	return ;
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0);
	while(cin>>n>>m)	solve();
	return 0;
}
posted @ 2026-08-05 10:44  深申  阅读(6)  评论(0)    收藏  举报