题解:P5189 [COCI 2009/2010 #5] ZUMA
做法
我写的详细一点。
每次消除一个区间,很容易让人想到用
但是当我们要将
如果能构造一个状态,使得这次合并在前面与
使用 P2135 中的技巧,
-
直接消除
j 和后面的x 个:f_{i,j,x}=f_{i,j-1,0}+\max(0,k-x-1) 。 -
假设
c_p=c_j ,将j 和后面的x 个与p 合并:f_{i,j,x}=f_{i,p,x+1}+f_{p+1,j-1,0} 。
那为什么只需要考虑
这样已经可以过了,但
代码
#include<bits/stdc++.h>
#define int long long
#define pii pair<int,int>
#define i128 __int128
#define ALL(x) x.begin(),x.end()
#define popcount(x) __builtin_popcountll(x)
#ifdef LOCAL
#include "debug.h"
#else
#define debug(...) 42
#endif
using namespace std;
const int INF=1e18;
const int N=105;
const int MOD=1e9+7,MOD2=998244353;
int n,k,a[N],f[N][N][6];//和j后面本来就存在的k个一起消除
void solve_(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int len=1;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
for(int x=0;x<k;x++){
f[i][j][x]=f[i][j-1][0]+max(0ll,k-x-1);
for(int p=i;p<j;p++){
if(a[p]==a[j]){
f[i][j][x]=min(f[i][j][x],f[i][p][min(k-1,x+1)]+f[p+1][j-1][0]);
}
}
}
}
}
cout<<f[1][n][0]<<"\n";
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int testcase,multitest=0;
if(multitest)cin>>testcase;
else testcase=1;
while(testcase--){
solve_();
}
return 0;
}