CF1312 E. Array Shrinking (区间dp)

一道(对我来说)比较迷的区间dp,后来看到大佬的题解才明白是怎么回事

我们都知道传统的区间dp写法是这样的

for(int len = 1;len<=n;len++){//枚举长度
        for(int j = 1;j+len<=n+1;j++){//枚举起点,ends<=n
            int ends = j+len - 1;
            for(int i = j;i<ends;i++){//枚举分割点,更新小区间最优解
                dp[j][ends] = min(dp[j][ends],dp[j][i]+dp[i+1][ends]+something);
            }
        }
  }

首先为什么判定是区间dp呢?
一是看数据在500以内,暗示时间复杂度 n^3;
二是存在明显的区间合并操作:左右相等后合并为一个数+1(something)

而这一题和普通的区间dp有什么区别呢
首先,维护的是区间最小值而非前缀和,因而dp初值要设为无穷大
其次,我们需要维护另一个类似于案例中dp数组一样的功能,即合并区间再加一
代码如下:

#include
using namespace std;
const int N = 5e2+5;
int dp[N][N],now[N][N],a[N];
int main()
{
   int n;
   cin>>n;
   for(int i=1;i<=n;i++)
   	for(int j=1;j<=n;j++)
   		dp[i][j] = 0x3f3f3f3f;
   for(int i=1;i<=n;i++)
   {
   	dp[i][i] = 1;
   	cin>>a[i];
   	now[i][i] = a[i]; 
   }
   for(int len=1;len<=n;len++)
   {
   	for(int i = 1;i+len<=n+1;i++)
   	{
   		int end = i+len-1;
   		for(int j = i;j < end;j++){//now充当原先dp的作用,现在的dp充当记录者
   			if(dp[i][j]==1&&dp[j+1][end]==1&&now[i][j]==now[j+1][end])
   			{
   				dp[i][end] = 1;now[i][end] = now[i][j]+1;
   			}
   			
   			dp[i][end] = min(dp[i][end],dp[i][j]+dp[j+1][end]);
   		}
   		
   	}
   }
   cout<<dp[1][n]<<endl;
} 

你可能感兴趣的:(ACM)