Educational Codeforces Round 38 F. Erasing Substrings DP

Description
给你一个长度为n的串,K次操作 ( K = ⌊ l o g 2 ​ n ⌋ ) (K=⌊log2​n⌋) (K=log2n),第i次操作去掉长度为2i−1的串,求最后剩下的字典序最小的串。


Sample Input
adcbca


Sample Output
aba


首先它是不会有覆盖的情况的,
然后你考虑DP吧,设f[i][j]为有i位,删除的状态为j的最优字符串。
可以 O ( n 3 l o g n ) O(n^3log n) O(n3logn),考虑用hash来优化它,可以做到 O ( n 2 l o g 2 n ) O(n^2log^2 n) O(n2log2n)
然后我认为这很极限了,但好像是会T的。
那你再贪婪的考虑一下,对于所有长度为i的,你肯定是选取字典序最优的。
于是就可以把这个转成一个bool,dp[i][j]表示长度为i的状态为j是否最优。
具体转移看代码吧。。。
哦,那你就可以 O ( n 2 l o g n ) O(n^2log n) O(n2logn)


#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long LL;
int _min(int x, int y) {return x < y ? x : y;}
int _max(int x, int y) {return x > y ? x : y;}
int read() {
	int s = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
	return s * f;
}

bool f[5100][5100];
char ss[5100];

int main() {
	scanf("%s", ss + 1);
	int n = strlen(ss + 1);
	int u = log2(n);
	for(int i = 0; i < (1 << u); i++) f[0][i] = 1;
	for(int i = 1; i <= n - (1 << u) + 1; i++) {
		int minn = 26;
		for(int j = 0; j < (1 << u); j++) f[i][j] = f[i - 1][j];
		for(int j = 0; j < (1 << u); j++) if(f[i][j]) minn = _min(minn, ss[i + j] - 'a' + 1);
		for(int j = 0; j < (1 << u); j++) if(f[i][j] && minn != ss[i + j] - 'a' + 1) f[i][j] = 0;
		for(int j = 0; j < (1 << u); j++) {
			for(int k = 1; k <= u; k++) if((j >> k - 1 & 1)){
				f[i][j] |= f[i][j ^ (1 << k - 1)];
			}
		} printf("%c", minn + 'a' - 1);
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值