杭电多校HDU 6586 String(序列自动机 贪心)题解
Posted kirinsb
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了杭电多校HDU 6586 String(序列自动机 贪心)题解相关的知识,希望对你有一定的参考价值。
题意:
给你一个串,现需要你给出一个子序列,满足26个约束条件,\\(len(A_i) >= L_i\\) 且 \\(len(a) <= R_i\\), \\(A_i\\)为从a到z的26个字母。
思路:
先用序列自动机(?)构造出某个位置后每个字母的个数,每个字母 的第一个位置。
然后每次贪心地加入最小的字符,加入的条件为当前字母加入后,后面的字符满足剩余的条件。
即剩余的字母在不超R_i的情况下能构成k长度的串,剩余的字母\\(A_i+\\)已拿取字母\\(A_i >= L_i\\)且满足\\(L_i\\)所需的长度小于剩余可添加长度。
官方题解:
代码:
#include<cstdio>
#include<set>
#include<cmath>
#include<stack>
#include<vector>
#include<queue>
#include<cstring>
#include<string>
#include<sstream>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 1e5 + 5;
const ll INF = 1e18;
int nex[maxn][30];
char s[maxn];
int len, k;
int l[30], r[30];
int cnt[maxn][30], getnum[30];
char ans[maxn];
bool check(int pos, int nowlen)
int len = 0;
int dis = 0;
for(int i = 0; i < 26; i++)
if(getnum[i] + cnt[pos][i] < l[i]) return false;
len += getnum[i] + min(r[i] - getnum[i], cnt[pos][i]);
dis += max(0, l[i] - getnum[i]);
if(len < k) return false;
if(dis > k - nowlen) return false;
return true;
int main()
while(~scanf("%s%d", s + 1, &k))
len = strlen(s + 1);
for(int i = 0; i < 26; i++)
scanf("%d%d", &l[i], &r[i]);
memset(nex[len], -1, sizeof(nex[len]));
memset(cnt[len], 0, sizeof(cnt[len]));
for(int i = len - 1; i >= 0; i--)
for(int j = 0; j < 26; j++)
nex[i][j] = nex[i + 1][j];
cnt[i][j] = cnt[i + 1][j];
nex[i][s[i + 1] - 'a'] = i + 1;
cnt[i][s[i + 1] - 'a']++;
memset(getnum, 0, sizeof(getnum));
int pos = 0, tot = 0;
bool ok = true;
while(pos <= len && tot < k)
bool can = false;
for(int i = 0; i < 26; i++)
if(nex[pos][i] != -1 && getnum[i] < r[i])
getnum[i]++;
if(check(nex[pos][i], tot + 1))
can = true;
ans[tot++] = i + 'a';
pos = nex[pos][i];
break;
getnum[i]--;
if(!can)
ok = false;
break;
ans[tot] = '\\0';
if(ok) printf("%s\\n", ans);
else printf("-1\\n");
return 0;
以上是关于杭电多校HDU 6586 String(序列自动机 贪心)题解的主要内容,如果未能解决你的问题,请参考以下文章
2019杭电多校第一场 Operation HDU - 6579