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;
}

浙公网安备 33010602011771号