题意:
给你一个字符串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;
}