http://codeforces.com/contest/724/problem/D
题目大意:给你一个串,从串中挑选字符,挑选是有条件的,按照这个条件所挑选出来的字符集合sort一定是最后选择当中最小的。
从pos=0开始挑选,每次挑选pos~pos+m-1这些位置中的字符,然后下一次再从之前挑选字符的位置开始的后面的m个中进行挑选。
思路:先贪心,按照字典序,每次找到该范围区间内最小的字符,因为该字符一定是串中的一部分,所以必然会被挑选的,于是我们先把这个pos的字符放入集合,并且对挑选过的位置做上标记。按照之前的方法可以先得到了一个集合,但是该集合不一定是最小的,例如m=2的时候cbbadca你前面挑选的集合为baca,但是你会发现还有一个b,如果放入的话字典序会更小,所以我们先得到目前集合中最大的字符,令他为ch,再for一遍把比ch小的再给放进来就好了。
说一下树状数组的作用,因为统计到末尾的时候,我不知道是直接结束还是再放入末尾区间内的某个字母,所以我利用树状数组统计了一下前面所有字符出现的次数,然后查询区间比末尾区间最小的字符串大的字符是否存在,如果存在就放入。
//看看会不会爆int!数组会不会少了一维! //取物问题一定要小心先手胜利的条件 #include <bits/stdc++.h> using namespace std; #define LL long long #define ALL(a) a.begin(), a.end() #define pb push_back #define mk make_pair #define fi first #define se second #define haha printf("haha ") const int maxn = 100000 + 5; int n, chlen; char ch[maxn]; int tree[200 + 5]; vector<char> v; char s[maxn]; bool vis[maxn]; void update(int x, int val = 1){ for (int i = x; i <= 200; i += i & -i){ tree[i] += val; } } int sum(int x){ int ans = 0; for (int i = x; i > 0; i -= i & -i){ ans += tree[i]; } return ans; } ///①并不是越长越好 ②最短长度是已经确定了的③所选出来的一定要比最短的那个的字典序要小 ///目标,长度短,字典序短 void solve(){ int pos = 0, slen = strlen(s); char minich = ch[pos]; for (int i = pos + 1; i < n; i++){ if(minich >= ch[i]){minich = ch[i], pos = i;} } vis[pos] = true; v.pb(minich); while (pos < chlen){ int minipos = pos + 1; minich = ch[minipos]; for (int i = minipos + 1; i <= min(chlen, pos + n); i++){ if (minich >= ch[i]){minich = ch[i], minipos = i;} } if (pos + n > chlen){ int val = sum(200) - sum(minich); if (val == 0) break; } vis[minipos] = true; v.pb(minich); update(minich); pos = minipos; } sort(ALL(v)); char maxch = v[v.size() - 1]; for (int i = 0; i <= chlen; i++){ if (!vis[i] && maxch > ch[i]){ vis[i] = true; v.pb(ch[i]); } } } int main(){ while (scanf("%d", &n) == 1){ memset(vis, false, sizeof(vis)); memset(tree, 0, sizeof(tree)); memset(s, 0, sizeof(s)); memset(ch, 0, sizeof(ch)); scanf("%s", ch); chlen = strlen(ch); if (n > chlen) {printf(" "); continue;} chlen--; int cnt = 0; for (int i = 2; i <= chlen; i += 2){ s[cnt++] = ch[i]; } solve(); sort(ALL(v)); for (int i = 0; i < v.size(); i++){ printf("%c", v[i]); } printf(" "); v.clear(); } return 0; }