https://codeforces.com/problemset/problem/1312/E
傻逼DP又写了快40分钟,迟早药丸
这题之前总是按传统的区间dp想维护i,j的最多合并次数,怎么维护左右是否能合并去了
然而事实上是要想到一个结论,那就是如果一个区间可以合并成一个数字,那么这个数字是定值,然后这个东西可以预处理
那么就维护num[i][j]=k表示i,j合并以后能得到一个k,如果k=0,表示不能合并到一起
接下来维护dp[i]表示前i个数字能合并成最少多少个数字
#include<bits/stdc++.h>
using namespace std;
const int maxl=510;
int n,m,ans;
int a[maxl],dp[maxl];
int num[maxl][maxl];
char s[maxl];
inline void prework()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),num[i][i]=a[i];
}
inline void mainwork()
{
int j;
for(int len=1;len<=n;len++)
for(int i=1;i+len<=n;i++)
{
j=i+len;
for(int k=i;k<j;k++)
if(num[i][k]==num[k+1][j] && num[i][k]>0)
num[i][j]=num[i][k]+1;
}
for(int i=1;i<=n;i++)
{
dp[i]=dp[i-1]+1;
for(int j=1;j<=i;j++)
if(num[j][i]>0)
dp[i]=min(dp[i],dp[j-1]+1);
}
}
inline void print()
{
printf("%d",dp[n]);
}
int main()
{
int t=1;
//scanf("%d",&t);
for(int i=1;i<=t;i++)
{
prework();
mainwork();
print();
}
return 0;
}