[JSOI2007]祖玛

做题时间:2022.9.28

给定一排 N 个整数,可以向之间插入任意一个整数,得到相邻的多于2个相同的整数就可以把他们消除掉,其余整数按顺序合并起来,也可以继续消除(一开始就连续的3个及以上的整数是不能消除的),问最少插入多少个整数使得所有整数都被消除完。

第一行一个整数 N

第二行 N 个整数 ai

一行一个整数表示答案

区间dp

消除后剩余的整数连接成一个连续的区间,因此可以使用区间dp,首先可以将原序列相邻的相同的整数合并到 sici 中(si 表示数的大小,ci 表示数的个数),定义 fi,j 表示消除 [i,j] 的最小代价。首先,可以通过两个区间消除合并得到,即:

fi,j=min(fi,k+fk+1,j)

其次,若 si=sj,表示 [i+1,j1] 这一段消除后可以合并 si,sj 再进行消除,即:

fi,j=min(fi+1,j1+(ci+cj2))

#include<cstdio>
#include<iomanip>
#include<cstring>
using namespace std;
const int N=550;
int f[N][N],a[N],n;
int s[N],cnt[N],ed;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
s[++ed]=a[1],cnt[1]=1;
for(int i=2;i<=n;i++){
if(a[i]==a[i-1]) cnt[ed]++;
else{
s[++ed]=a[i];
cnt[ed]=1;
}
}
memset(f,63,sizeof f);
for(int i=1;i<=ed;i++){
if(cnt[i]>1) f[i][i]=1;
else f[i][i]=2;
}
for(int len=2;len<=ed;len++){
for(int i=1;i<=ed-len+1;i++){
int j=i+len-1;
if(s[i]==s[j]) f[i][j]=min(f[i][j],f[i+1][j-1]+(cnt[i]+cnt[j]<=2));
for(int k=i;k<j;k++){
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
}
}
}
if(f[1][ed]==3) printf("2\n");
else printf("%d\n",f[1][ed]);
return 0;
}

本文作者:lxzy

本文链接:https://www.cnblogs.com/Unlimited-Chan/p/16740706.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   lxzy  阅读(41)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.