CF946E

为了让我们构造出来的结果尽量大而又不超过给定的 \(s\),当我们构造的串长度跟 \(s\) 相同时,就可以知道存在一个 \(k\) 满足我们构造出来的串前 \(k-1\) 位和 \(s\) 一样,第 \(k\) 位比 \(s_k\) 小,然后后面 \(k+1\)\(n\) 位能使串满足定义又尽量大。

所以我们从高位到低位枚举那个被修改小的位置 \(k\),然后从大到小枚举它被改成的数字。接下来如何判断成立与否了,因为前 \(k-1\) 位我们填的都是 \(s\) 串中对应的数,第 \(k\) 位又是我们枚举出来的,而我们又要满足所有数字出现次数为偶数次,所以前 \(k\) 位出现次数为奇数的数字都得在后面出现奇数次。所以,如果出现为奇数次的数字数量 \(x\) 大于 \(n-k\),则无法构造出来,否则可以。

至于构造方法,就是最后 \(x\) 位从大到小填上那些需要补全为偶数次的数字,中间剩余的位置都填 \(9\) 即可。

统计一段前缀每种数字出现的奇偶次数可以预处理出来,所以总复杂度是线性的。

若找不到满足条件的等长串,则输出 \(n-2\)\(9\)

Code:

#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
int T;
int n, m;
int sum[N][10];
char s[N];

void solve() {
	scanf("%s", s + 1), n = strlen(s + 1);
	for (int i = 1; i <= n; ++i) {
		for (int j = 0; j < 10; ++j)
			sum[i][j] = sum[i - 1][j] ^ (s[i] - '0' == j);
	}
	for (int i = n; i; --i)
		for (int j = s[i] - '0' - 1; ~j; --j) {
			if (i == 1 && j == 0) continue;
			int tmp = 0;
			for (int k = 0; k < 10; ++k) tmp += sum[i - 1][k] ^ (j == k);
			if (tmp <= n - i) {
				for (int k = 1; k < i; ++k) putchar(s[k]);
				putchar(j + '0');
				for (int k = i + 1; k <= n - tmp; ++k) putchar('9');
				for (int k = 9; ~k; --k)
					if (sum[i - 1][k] ^ (j == k)) putchar(k + '0');
				printf("\n"); return;
			}
		}
	for (int i = 1; i <= n - 2; ++i) putchar('9');
	printf("\n");
}

int main() {
	scanf("%d", &T);
	while (T--) solve();
	return 0;
}
posted @ 2022-10-19 20:49  Kobe303  阅读(17)  评论(0编辑  收藏  举报