Codeforces 1312E. Array Shrinking

Codeforces 1312E. Array Shrinking

题意:

有一个序列,你可以选择一对相邻的数字\(a_i=a_{i+1}\),然后将这两个数字换为\(a_i+1\)

问最后最少能留下多少个数字。

思路:

似乎没有好的贪心策略,所以确定是dp应该没问题。

我们设\(g(i,j)\)表示在区间\([i,j]\)范围内的那个相同的数字是什么。

那么我们可以用区间dp的方式预处理一下\(g\)

当然在预处理的过程中要记录下所有区间的信息。

\(f(i)\)表示前\(i\)个数字的答案,然后枚举所有区间信息更新答案就好了。

还是看代码吧。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 500+10;
int g[maxn][maxn];

struct Node{
    int l, r;
}p[maxn*maxn];
bool cmp(Node a, Node b){
    return a.r < b.r;
}
int tot;

int n;
int f[maxn];

int main()
{
    scanf("%d", &n);
    for(int i = 1, x; i <= n; i++)
    {
        scanf("%d", &x);
        g[i][i] = x;
        p[++tot] = {i, i};
    }
    for(int len = 2; len <= n; len++)
        for(int l = 1; l <= n-len+1; l++)
    {
        int r = len+l-1;
        for(int k = l; k < r; k++)
        if(g[l][k]&&g[k+1][r]&&g[l][k]==g[k+1][r])
        {
            g[l][r] = g[l][k]+1;
            p[++tot] = {l, r};
            break;
        }
    }

    sort(p+1, p+1+tot, cmp);
    for(int i = 1, j = 1; i <= n; i++)
    {
        f[i] = i;
        while(p[j].r == i)
        {
            f[i] = min(f[i], f[p[j].l-1]+1);
            j++;
        }
    }
    //for(int i = 1; i <= tot; i++)
    //printf("%d %d\n", p[i].l, p[i].r);

    cout << f[n] << endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zxytxdy/p/12454472.html