CF 938F Erasing Substrings DP 贪心

题意:

给你一个字符串S,你需要执行次操作,每次删除一个长度为2^(i-1)的子串。问最后字典序最小是多少。

题解:

最后一定剩余|S| - 2^k + 1长度的串,从前往后考虑,我们对当前的字符,一定要越小越好。

这样我们可以定义一个状态dp[i][j]表示当前删除了j个字符,还剩下i个字符的最小字符串。

但是我们发现没有必要这么做,因为当前如果不是长度为i的最优的串,那么就没用了。

我们只需定义dp[i][j]为删除了j个字符还剩i个字符时是否可能是最优的串,然后枚举删除的长度,从前面转移过来,选择一个最小的字符,然后就是当前的状态了。

可以通过滚动第二维, 达到删除连续串的作用。

代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <bitset>
#include <map>
#include <vector>
#include <stack>
#include <set>
#include <cmath>
#ifdef LOCAL
#define debug(x) cout<<#x<<" = "<<(x)<<endl;
#else
#define debug(x) 1;
#endif

#define chmax(x,y) x=max(x,y)
#define chmin(x,y) x=min(x,y)
#define lson id<<1,l,mid
#define rson id<<1|1,mid+1,r
#define lowbit(x) x&-x
#define mp make_pair
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, int> pii;

const ll MOD = 1e9 + 7;
const double eps = 1e-10;
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fll;
const int MAXN = 5e3 + 5;

char s[MAXN];
int d[MAXN];

int main() {
#ifdef LOCAL
    freopen ("input.txt", "r", stdin);
#endif
    scanf("%s", s + 1);
    int n = strlen(s + 1);
    int l = log2(n + eps);
    int m = n - (1<<l) + 1;
    for(int i = 0; i < (1<<l); i++) d[i] = 1;
    for(int i = 1; i <= m; i++) {
        char c = 'z';
        for(int j = 0; j < (1<<l); j++) {
            if(d[j]) {
                for(int k = 0; k < l; k++) d[j | (1<<k)] = 1;
            }
        }
        for(int j = 0; j < (1<<l); j++) if(d[j]) c = min(c, s[i + j]);
        for(int j = 0; j < (1<<l); j++) d[j] &= (s[i + j] == c);
        putchar(c);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/c6376315qqso/article/details/82504120
今日推荐