Codeforces 1312E. Array Shrinking(区间DP 栈)

简介: Codeforces 1312E. Array Shrinking(区间DP 栈)

linkkk

题意:

给出一个长度为n的序列,对于相同相邻的两个数x可以替换为一个数x + 1,问该序列的最短长度是多少。

n < = 500

思路:

看到数据范围不难想到是个区间dp

d p [ l ] [ r ]表示区间[ l , r ]能够合并成的最短序列长度。

那么d p [ l ] [ r ] = m i n ( d p [ l ] [ k ] + d p [ k + 1 ] [ r ] )

什么时候[ l , k ]和[ k + 1 , r ]也可以合并呢?当两个区间的最短长度为1并且剩下的数相同时。

记b [ l ] [ r ]表示区间[ l , r ]合并后剩余的数

就可以转移了。

时间复杂度O ( n 3 )

代码:

// Problem: E. Array Shrinking
// Contest: Codeforces - Educational Codeforces Round 83 (Rated for Div. 2)
// URL: https://codeforces.com/problemset/problem/1312/E
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)
#include<iostream>
#include<cstdio> 
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<sstream>
using namespace std;
typedef long long ll;
const int maxn=2e5+100;
int a[510],b[510][510],dp[510][510];
int main() {
  int n;cin>>n;
  for(int i=1;i<=n;i++) cin>>a[i];
  for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++){
      dp[i][j]=j-i+1;
      if(i==j) b[i][i]=a[i];
    }
  for(int len=1;len<=n;len++){
    for(int l=1;l+len-1<=n;l++){
      int r=l+len-1;
      for(int k=l;k<=r-1;k++){
        dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]);
        if(dp[l][k]==1&&dp[k+1][r]==1&&b[l][k]==b[k+1][r]){
          dp[l][r]=1;
          b[l][r]=b[l][k]+1;
        }
      }
    }
  }
  cout<<dp[1][n]<<endl;
  return 0;
}

思路:

考虑用另一种表示状态:d p [ i ]表示[ 1 , i ]合并后的最短长度,那么最后的答案便是[ 1 , n ]

转移的话,如果说[ k , i ]可以合并为一个数,那么显然d p [ i ] = d p [ k − 1 ] + 1

问题就转化为了如何快速判断区间[ k , i ]能否合并为一个数。

延伸出两种思路:


借助括号匹配的思想,运用栈来判断。具体做法为:枚举右端点,对于每一个右端点,维护一个栈,然后倒着向前枚举,如果当前元素x和栈顶元素相同,弹出栈顶,说明两者合并变为了x + 1。最后如果说栈的大小为1说明该段区间可以合并为一个数。

用区间d p来解,f [ l ] [ r ]表示区间[ l , r ]合并后的数为多少,如果为0则说明无法合并为一个数。枚举中间点,如果说f [ l ] [ k ] = = f [ k + 1 ] [ r ] 则f [ l ] [ r ] = f [ l ] [ k ] + 1

前者的时间复杂度是O ( n 2 ),后者为O ( n 3 )

代码:

// Problem: E. Array Shrinking
// Contest: Codeforces - Educational Codeforces Round 83 (Rated for Div. 2)
// URL: https://codeforces.com/problemset/problem/1312/E
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)
#include<iostream>
#include<cstdio> 
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<sstream>
using namespace std;
typedef long long ll;
const int maxn=2e5+100;
int a[510],b[510][510],dp[510];
int main() {
  int n;cin>>n;
  for(int i=1;i<=n;i++) cin>>a[i];
  for(int r=1;r<=n;r++){
    dp[r]=dp[r-1]+1;
    stack<int>st;
    st.push(a[r]);
    for(int l=r-1;l;l--){
      int now=a[l];
      while(1){
        if(st.empty()){
          st.push(now);break;
        }
        if(now==st.top()) st.pop(),now++;
        else{
          st.push(now);break;
        }
      }
      if(st.size()==1) dp[r]=min(dp[r],dp[l-1]+1);
    }
  }
  cout<<dp[n]<<endl;
  return 0;
}

区间dp

// Problem: E. Array Shrinking
// Contest: Codeforces - Educational Codeforces Round 83 (Rated for Div. 2)
// URL: https://codeforces.com/problemset/problem/1312/E
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)
#include<iostream>
#include<cstdio> 
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<sstream>
using namespace std;
typedef long long ll;
const int maxn=2e5+100;
int a[510],f[510][510],dp[510];
int main() {
  int n;cin>>n;
  for(int i=1;i<=n;i++) cin>>a[i],f[i][i]=a[i];
  for(int len=1;len<=n;len++)
    for(int l=1;l+len-1<=n;l++){
      int r=l+len-1;
      for(int k=l;k<=r;k++)
        if(f[l][k]!=0&&f[l][k]==f[k+1][r])
          f[l][r]=f[l][k]+1;
    }
  memset(dp,0x3f,sizeof dp);
  dp[0]=0;
  for(int r=1;r<=n;r++)
    for(int l=1;l<=r;l++)
      if(f[l][r]!=0) dp[r]=min(dp[r],dp[l-1]+1);
  cout<<dp[n];
  return 0;
}

总结:

d p状态不同决定了时间复杂度的不同,对于某个d p状态来说,又会有好几种解法。

参考:

博客1

博客2




目录
相关文章
codeforces 318 A.Even Odds B.Sereja and Array
codeforces 318 A.Even Odds B.Sereja and Array
38 0
|
人工智能
codeforces 315 B.Sereja and Array
codeforces 315 B.Sereja and Array
46 0
codeforces 299 A. Ksusha and Array
题目就是让你找出一个数组中可以将这个数组中所有数整除的数,很明显,如果存在,这个数肯定是最小的一个。
46 0
|
7月前
|
Python
使用array()函数创建数组
使用array()函数创建数组。
144 3
|
21天前
|
存储 Go 索引
go语言中的数组(Array)
go语言中的数组(Array)
101 67
|
2月前
|
人工智能 前端开发 JavaScript
拿下奇怪的前端报错(一):报错信息是一个看不懂的数字数组Buffer(475) [Uint8Array],让AI大模型帮忙解析
本文介绍了前端开发中遇到的奇怪报错问题,特别是当错误信息不明确时的处理方法。作者分享了自己通过还原代码、试错等方式解决问题的经验,并以一个Vue3+TypeScript项目的构建失败为例,详细解析了如何从错误信息中定位问题,最终通过解读错误信息中的ASCII码找到了具体的错误文件。文章强调了基础知识的重要性,并鼓励读者遇到类似问题时不要慌张,耐心分析。
|
2月前
|
存储 Java
Java“(array) <X> Not Initialized” (数组未初始化)错误解决
在Java中,遇到“(array) &lt;X&gt; Not Initialized”(数组未初始化)错误时,表示数组变量已被声明但尚未初始化。解决方法是在使用数组之前,通过指定数组的大小和类型来初始化数组,例如:`int[] arr = new int[5];` 或 `String[] strArr = new String[10];`。
96 2
|
2月前
|
存储 JavaScript 前端开发
JavaScript Array(数组) 对象
JavaScript Array(数组) 对象
35 3
|
2月前
|
数据采集 JavaScript 前端开发
JavaScript中通过array.filter()实现数组的数据筛选、数据清洗和链式调用,JS中数组过滤器的使用详解(附实际应用代码)
JavaScript中通过array.filter()实现数组的数据筛选、数据清洗和链式调用,JS中数组过滤器的使用详解(附实际应用代码)