题意:
小明写了一个大数字 n
,然后再这个数字后面又加了一个数字 k
, k
是 n
的位数
现在小明把完整的数字传给了小红, 但是在传输的过程中出现了意外,小红收到的数字的内容是打乱的, 现在知道的是小明还记得 大数字 n
的一部分,也就是他的字串,让你还原这个数字 n, 且让这个数字 n 尽可能的小。
记住,不能又前导零, 一个单个的 零 是允许的。
输入是小红收到的数
还有小明记住的数
思路:
有一点很容易想到, 这个 n 很大,也就是 n 的位数很多,但是 n 的位数这个数字的位数也就不超过8位, 所以我们就可以枚举 n 的位数这个数字的位数
。
- 首先判断这个位数是不是合法
- 如果合法
- 判断能不能找到最小的数输出。
- 如果合法
首先判断这个位数是不是合法,
我们枚举的位数 x
和 真正剩下的数lens - x
的位数是不是一样的,
如果是一样的,再看看枚举的位数可不可以由剩下的数组成。
如果位数合法判断能不能组成最小的数。
现在问题转化成了
有一些数字, 还有一个有数字组成的字符串t, 怎样组合才可以让组成的数最小。
首先考虑能不能组成数, 也就是剩下的数是不是都是 0,
如果都是 0, 0 的个数有多少个,
如果 0 的个数大于1,那就GG, 如果就 1 个, 直接输出来。
- 如果 t 的开头是 0, 单独输出来。 那么 t 就一定不是在总串的开头
- 如果 t 的开头不是 0, 我们就弄出来两个字符串
- t 在总串的开头
- t 不在总串的开头,这种情况有可能不存在,注意考虑,因为 剩余的数字中有可能只有0或者不剩余数字。
- 最终两个串比较一下就好了。
反思:
一开始就没有想到过用两个串进行比较的事,
一开始想的就是直接把这个最小的串构造出来。就导致要考虑的细节特别多。 这里少一个东西,那里少一个东西。
下次再遇到这样的题,
给你一些数字, 和一个字符串,构造一个最小的数字出来,
两步走,
- 判断t串开头是不是 0,是 0 直接处理
- 不是 0, 构造两个串出来,进行比较。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+100;
void dbg() {cout << endl;}
template<typename T, typename... A> void dbg(T a, A... x) {cout << a << ' '; dbg(x...);}
#define logs(x...) {cout << #x << " -> "; dbg(x);}
int n,m,lens,lent,a[10],b[10],c[10];
char s[N],t[N],l[N],r[N];
bool solve(int x){ //判断当前数字的位数是不是满足条件。位数最多是 1e6, 所以 k 最大就是7位。一个一个判断。
for (int i = 0; i < 10; ++i)
c[i] = a[i];
if (lens - x <= 0){
return false;
}
int tmp = lens - x,y,len = 0;
while(tmp){
y = tmp % 10;
len++;
c[y]--;
if (c[y] < 0) return false;
tmp /= 10;
}
if (len != x) return false; //我假定的位数 和 真实的位数是不是一样的,如果不是那就false。
return true;
}
void put0(){ // t 串开头是 0 的情况。
bool vis = 1;
for (int i = 1; i < 10; ++i){
if (c[i] && vis){
printf("%d",i);
vis = 0;
for (int j = 1; j <= c[0]; ++j)
printf("0");
printf("%s",t+1);
for (int j = 1; j < c[i]; ++j)
printf("%d",i);
} else
for (int j = 1; j <= c[i]; ++j)
printf("%d",i);
}
if (vis) printf("%s\n",t+1);//如果剩下的数字全在t串中,要单独考虑
printf("\n");
return;
}
bool put(int emmm){
int x = t[1] - '0',y = 0;
for (int i = 1; i < 10; ++i)
y += c[i];
y += x;
if (y == 0 && emmm > 1) return 0; //判断是不是全零, 如果是一个零还是满足条件的,否则不满足条件。
if (x == 0){
put0(); // 首先判断 t 串的开头,不能是零, 不然是零的话不可以放在总串的开头。
return 1;
}
y = 0;
for (int i = 1; i <= lent; ++i)
l[y++] = t[i];
for (int i = 0; i < 10; ++i)
for (int j = 1; j <= c[i]; ++j)
l[y++] = i + '0';
y = 0;
for (int i = 1; i <= 9; ++i)
if (c[i]){
r[y++] = i + '0';
c[i] --;
break;
}
if (y == 0){ // 判断 去除了T 串, 剩下的数字不能当头, 如果不能就直接输出 t 串当头。
printf("%s\n",l);
return 1;
}
x = t[1] - '0';
for (int i = 2; i <= lent; ++i){
if (t[i] > t[i-1]) break;
if (t[i] < t[i-1]) {
x--;
break;
}
}
for (int i = 0; i < 10; ++i){
for (int j = 1; j <= c[i]; ++j)
r[y++] = i + '0';
if (i == x){
for (int j = 1; j <= lent; ++j)
r[y++] = t[j];
}
}
if (strcmp(l,r) <= 0){ //两个串进行比较。
printf("%s\n",l);
} else printf("%s\n",r);
return 1;
}
int main(){
scanf("%s",s+1);
scanf("%s",t+1);
lens = strlen(s+1);
lent = strlen(t+1);
for (int i = 1; i <= lens; ++i)
a[s[i] - '0'] ++;
for (int i = 1; i <= lent; ++i){
a[t[i] -'0'] --;
b[t[i] -'0'] ++;
}
for (int i = 7; i > 0; --i){
if (solve(i)) {
if (put(lens - i)) return 0;
}
}
return 0;
}