区间dp
虚拟比赛时没有做出来,看题解时,第一句话就让我反应过来了!
可恶!!!!
最终的答案假如[a1,a2,a3]那么a1,a2,a3一定是三个区间合并出来的
也就是,我们给数组划分几个区间,这些区间都可以合并成一个数。
找到划分区间的最小数。
问题一下子就简化了!!
定义dp[i][j],如果[i,j]不可以合并成一个数那么dp[i][j]=inf
否则dp[i][j] = 最终合并的这个数
转移dp[i][j]=dp[i][k]+1 if dp[i][k]!=inf&&dp[k+1][j]!=inf&&dp[i][k]==dp[k+1][j]
其实就是划分更两个区间看。
当dp维护成功时,其实最终答案也就出来了。
再来一次dp
ans[i]为[1,i]操作中的最少剩余元素
如果dp[1][i]!=inf ans[i]=1
否则枚举更新ans[i] = min(ans[j]+1 if dp[j+1][i]!=inf)
答案就是ans[n]了
#include<iostream> #include<algorithm> #include<cstring> using namespace std; const int inf = 1e9; int dp[600][600]; int res[600]; int main(){ int n;scanf("%d",&n); for (int i=1;i<=n;++i)for (int j=1;j<=n;++j)dp[i][j]=inf; for (int i=1;i<=n;++i)scanf("%d",&dp[i][i]); for (int len = 2;len<=n;++len){ for (int i=1;i+len-1<=n;++i){ int lft = i,rgt = i+len-1; for (int j=lft;j<rgt;++j){ if (dp[lft][j]!=inf&&dp[lft][j]==dp[j+1][rgt]){ dp[lft][rgt] = dp[lft][j]+1; break; } } } } for (int i=1;i<=n;++i)res[i]=inf; for (int i=1;i<=n;++i){ if (dp[1][i]!=inf){ res[i]=1; continue; } for (int j=i-1;j>=0;--j) if (dp[j+1][i]!=inf) res[i]=min(1+res[j],res[i]); } printf("%d\n",res[n]); }