F1.F2. Nearest Beautiful Number
#739 (Div. 3)F2. Nearest Beautiful Number
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
It is a complicated version of problem F1. The difference between them is the constraints (F1: k≤2, F2: k≤10).
You are given an integer n. Find the minimum integer x such that x≥n and the number x is k-beautiful.
A number is called k-beautiful if its decimal representation having no leading zeroes contains no more than k different digits. E.g. if k=2, the numbers 3434443, 55550, 777 and 21 are k-beautiful whereas the numbers 120, 445435 and 998244353 are not.
Input
The first line contains one integer t (1≤t≤104) — the number of test cases. Then t test cases follow.
Each test case consists of one line containing two integers n and k (1≤n≤109, 1≤k≤10).
Output
For each test case output on a separate line x — the minimum k-beautiful integer such that x≥n.
- 输入
6
2021 3
177890 2
34512 3
724533 4
998244353 1
12345678 10 - 输出
2021
181111
34533
724542
999999999
12345678
对于这道题目,我们首先要知道我们的思考策略,首先我们判断这个数字是不是需要进行更改操作,如果本身就已经满足条件,就可以直接输出,否则,我们找到需要更改的第一位数字,首先,我们要清楚自己的选择策略,并不是从高位开始,一个一个选,而是从低位到高位开始判断(check),然后对这一位,我们有p+1~9这些选择(这一位数字是p),之所以没有p是因为如果这一位我们不需要改,那么这并不符合我们一开始的判断,我们是寻找改变的第一位数字,然后对于第一位后面的数字,我们判断不同数字的数量和k的关系,如果小于k那么后面直接全部赋值为0,否则就选择可以选择的最小值
#include <bits/stdc++.h>
using namespace std;
bool vis[15];
int k;
int check(string s)
{
int n = s.size();
memset(vis, 0, sizeof vis);
for (int i = 0; i <= n; i++)
vis[s[i] - '0'] = 1;
int sum = 0;
for (int i = 0; i < 10; i++)
if (vis[i])
sum++;
return sum;
}
string getans(string s,int num)
{
int n = s.size();
int z = check(s);
if(z<k)
{
for(int i=0;i<num;i++)
s+=to_string(0);
return s;
}
int minn = 10;
for (int j = 0; j < n; j++)
minn = min(minn, s[j] - '0');
for (int j = 0; j < num; j++)
s += to_string(minn);
return s;
}
int main()
{
int T;
cin >> T;
while (T--)
{
int a;
cin >> a;
cin >> k;
int n = to_string(a).size();
string ans;
if (check(to_string(a)) <= k)
printf("%d\n", a);
else
{
int fla=0;
for (int num = 0;num<n&&fla!=1;num++)
{
int p = a % 10+1;
for (int i = p; i < 10; i++)
{
int t = a / 10 * 10 + i;
if (check(to_string(t)) <= k)
{
cout<<getans(to_string(t), num)<<endl;
fla=1;
break;
}
}
a /= 10;
}
}
}
}
下面是简单版本的题解,其实就是枚举每一个数,然后进行排序,二分寻找答案,然后输出,值得一提的是:在枚举的时候比较聪明的方法就是二进制枚举,还有边界9位数的界限问题
#include <bits/stdc++.h>
#define ll long long
const int N = 1e7 + 10;
using namespace std;
ll ans[N];
int cnt;
ll ans1[N];
void init()
{
unordered_map<ll, bool> mp;
for (int i = 0; i <= 9; i++) //枚举第一个数字
{
for (int j = 0; j <= 9; j++) //枚举第二个数字
{
for (int len = 1; len <= 9; len++) //枚举数字长度
{
for (int k = 0; k < (1 << len); k++) //这是每一种的排列情况
{
int sum = 0;
int cc = 1;
for (int z = 0; z < len; z++) //这是分析每一位的选择 01进行判断是选第一个还是第二个
{
if (k & (1 << z))
sum += i * cc;
else
sum += j * cc;
cc *= 10;
}
if (!mp[sum]) //防止重复
{
ans[++cnt] = sum;
mp[sum] = true;
}
}
}
}
}
ans[++cnt]=1000000000; //这是边界处理的情况因为最大9位数
sort(ans + 1, ans + cnt + 1);
}
int main()
{
init();
int cnt1 = 0;
for (int i = 1; i < 10; i++)
{
int sum = 0;
for (int len = 1; len < 10; len++)
{
sum = sum * 10 + i;
ans1[++cnt1] = sum;
}
}
ans1[++cnt1]=1111111111;
sort(ans1 + 1, ans1 + 1 + cnt1);
int T;
cin >> T;
while (T--)
{
int n, k;
cin >> n >> k;
if (k == 1)
{
int cc = lower_bound(ans1 + 1, ans1 + 1 + cnt1, n) - ans1;
cout << ans1[cc] << endl;
}
else
{
int cc = lower_bound(ans + 1, ans + 1 + cnt, n) - ans;
cout << ans[cc] << endl;
}
}
}