现已加入每日暴力&构造 练习
这是day1
题意:给你\(n\)和\(k\),找到最小的\(\ge n\)且包含不超过\(k\)个字符的最小数字。
sol:找到\(n\)的最长的包含\(k\)个字符的前缀,如果这个前缀合起来就是\(n\),直接输出\(n\)即可。不然可以枚举合法前缀,将其加上1~9,使得非前缀部分全部变为前缀中最小的那个数字。
时间复杂度\(O(T\log^3 n)\)
#include<bits/stdc++.h>
using namespace std;
const int maxn = 20;
#define ll long long
ll top, stk[maxn], n, k, T;
bool vis[maxn];
bool check(int x) {
memset(vis, 0, sizeof(vis));
int cnt = 0;
while (x) {
if (!vis[x % 10]) {
vis[x % 10] = 1;
cnt++;
}
x /= 10;
}
return cnt <= k;
}
ll ans;
int main() {
scanf("%lld", &T);
while (T--) {
ans = 1999999999;
scanf("%lld%lld", &n, &k);
memset(vis, 0, sizeof(vis));
ll x = n;
top = 0;
int cnt = 0;
while (x) {
stk[++top] = x % 10;
x /= 10;
}
ll len = 0;
for (int i = top; i >= 1; i--) {
if (!vis[stk[i]]) {
vis[stk[i]] = 1;
cnt++;
if (cnt == k) break;
}
}
for (int i = top; i >= 1; i--) {
if (!vis[stk[i]]) break;
len = max(len, top - i + 1);
}
if (len == top) {
printf("%lld\n", n);
continue;
}
int pre = 0, mx = 0;
for (int i = top; i >= 1; i--) {
pre = pre * 10 + stk[i];
mx = 0;
for (int l = 1; l <= 9; l++) {
if (check(pre + l)) {
for (int j = 0; j <= 9; j++) {
if (vis[j]) {
mx = j;
break;
}
}
ll res = pre+l;
for (int j = i-1; j >= 1; j--) res = res * 10 + mx;
ans = min(res, ans);
}
}
}
printf("%lld\n", ans);
}
}