【题解】NOIp模拟:密码

题面
考虑贪心逐位确定,比如对于第一位,先看看最近的 a a 可不可以移动到当前位置上,可以就移动,否则就看看最近的 b b 可不可以,以此类推
如果最近的 a a 确定为当前位上的字符,那么我们确定后面一位的时候,这个 a a 不能用了,需要看第二近的 a a ,这个需要用模拟链表实现
对于判断这个字符时候能在限制步数下移动到当前位,可以用树状数组维护这个字符前面还剩多少字符

Code:

#include <bits/stdc++.h>
#define maxn 100010
#define int long long
using namespace std;
char s[maxn], ans[maxn];
int m, n, tree[maxn], head[maxn], nxt[maxn];

int lowbit(int x){ return x & -x; }
void add(int x, int y){ for (; x <= n; x += lowbit(x)) tree[x] += y; }
int query(int x){ int s = 0; for (; x; x -= lowbit(x)) s += tree[x]; return s; }

signed main(){
	scanf("%lld", &m);
	scanf("%s", s + 1);
	n = strlen(s + 1);
	for (int i = n; i; --i) nxt[i] = head[s[i]], head[s[i]] = i, add(i, 1);
	for (int i = 1; i <= n; ++i)
		for (char j = 'a'; j <= 'z'; ++j)
			if (head[j]){
				int x = query(head[j] - 1);
				if (x <= m){
					m -= x;
					add(head[j], -1);
					head[j] = nxt[head[j]];
					printf("%c", j);
					break;
				}
			}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ModestCoder_/article/details/108199377