4307. 数字重构
题目链接
4307. 数字重构
给定两个正整数 \(a\) 和 \(b\),均不含前导 \(0\)。
现在,请你对 \(a\) 进行重构,重新排列其各位数字顺序,得到一个不含前导 \(0\) 的新正整数。
要求新正整数在不超过 \(b\) 的前提下,尽可能大。
输出新正整数。
注意,我们允许新正整数等于 \(a\),即保持原样不变。
输入格式
第一行包含一个正整数 \(a\)。
第二行包含一个正整数 \(b\)。
两个输入数字均不含前导 \(0\)。
输出格式
一个不含前导 \(0\) 的正整数,表示答案。
数据保证一定有解。
数据范围
前 \(6\) 个测试点满足 \(1≤a,b≤10^9\)。
所有测试点满足 \(1≤a,b≤10^{18}\)。
输入样例1:
123
222
输出样例1:
213
输入样例2:
3921
10000
输出样例2:
9321
输入样例3:
4940
5000
输出样例3:
4940
解题思路
贪心
不可能存在 \(a\) 的位数比 \(b\) 的位数还大的情况,因为 \(a\) 不能有前导零且题目保证有解,当 \(a\) 的位数小于 \(b\) 的位数时最大值即为 \(a\) 的倒序,否则对于重构 \(a\) 来说,可以从高位开始枚举 \(9\sim 0\),当前面选上的数加上这个数再加上剩余的数组成的最小数小于等于 \(b\) 时,说明这个数可以选
- 时间复杂度:\(O(10\times loga\times loga)\)
代码
// Problem: 数字重构
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/4310/
// Memory Limit: 256 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
string a,b;
int cnt[10];
string get_min(int x)
{
string res;
for(int i=0;i<=9;i++)
if(i!=x)res+=string(cnt[i],i+'0');
else
res+=string(cnt[i]-1,i+'0');
return res;
}
int main()
{
cin>>a>>b;
if(a.size()<b.size())
{
sort(a.begin(),a.end(),greater<char>());
cout<<a;
return 0;
}
string res;
for(char c:a)cnt[c-'0']++;
for(int i=0;i<a.size();i++)
for(int j=9;~j;j--)
if(cnt[j]&&res+to_string(j)+get_min(j)<=b)
{
res+=to_string(j);
cnt[j]--;
break;
}
cout<<res;
return 0;
}