【CF1312E】Array Shrinking(dp)

傳送門

  • 題目:
    在這裏插入圖片描述
  • 思路:
    數組中的某些數可以通過執行多次題目中的操作最終歸爲1個數。
    先確定每個r(1rn)r(1≤r≤n)有哪些l(1lr)l(1≤l≤r)滿足[l,r][l,r]內的數可以歸爲1個數。在處理的時候可以先枚舉ll,這樣rr每次都只增加1。且[l,oldr][l,oldr]的結果已知,[l,newr][l,newr]只是在[l,oldr][l,oldr]在多考慮一個數字而已,用棧模擬。
    dp[i]dp[i]表示[1,i][1,i]內可以形成的答案數,dp[i]=min{dp[j1]+1}dp[i]=min\{dp[j-1]+1\},其中j是由前面的處理得到的滿足[j,i][j,i]內的數能歸爲1個數的下標。
    最終答案是dp[n]dp[n],時間複雜度O(n2)O(n^2)
  • ac代碼:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 550;
const ll mod = 998244353;
int n;
int dp[maxn], a[maxn];
vector<int> v[maxn];
stack<int> s;
bool check(int x)
{
    while(!s.empty() && s.top()==x)
    {
        x = x+1;
        s.pop();
    }
    s.push(x);
    if(s.size()==1) return true;
    else return false;
}
int main()
{
    //freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    for(int l = 1; l <= n; l++)
    {
        while(!s.empty()) s.pop();
        for(int r = l; r <= n; r++)
            if(check(a[r])) v[r].push_back(l);
    }
    for(int i = 1; i <= n; i++) dp[i] = INT_MAX;
    for(int r = 1; r <= n; r++)
        for(auto l : v[r])
            dp[r] = min(dp[r], dp[l-1]+1);
    printf("%d\n", dp[n]);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章