下一个序列 题解
题目描述
对于这个问题,你要写一个程序,这个程序读入一个大于零的十进制的数字(这个数字可能非常的大),输出下一个比它大的一个序列(原数字各个位上的数字重新排列的序列,同样也是十进制),例如:
123->132 279134399742->279134423799
有可能存在某数字不存在这样的下一个序列,例如:
987
输入格式
第一行有一个整数P,表示接下来有P组数据。
接下来有P行,每一行有两个整数。
第一个整数表示数据的编号(1,2,3,...,P),第二个整数表示读入的十进制数字。
输出格式
每组测试数据输出两个整数。
第一个整数表示数据的编号(1,2,3,...,P)。
第二个整数表示下一个比它大的序列。如果该组测试数据不存在下一个比它大的序列,输出BIGGEST。
样例输入
3
1 123
2 279134399742
3 987
样例输出
1 132
2 279134423799
3 BIGGEST
数据范围:
1≤P≤1000,
读入十进制数字的长度小于等于80
分析
毫无疑问,这是一道贪心题
先不管大佬的操作,我们来分析一下:
STEP1:
在什么情况下,要输出BIGGEST?也就是目前这个序列在他的全排列中最大,是什么呢?拿 123 举个栗子
它的全排列如下
123 132 213 231 321 312不难看出,当这个序列是递减时,它一定是最大的,没看懂的找胡帅。另外,当序列长度为1时,也应该输出BIGGEST
STEP2:
如果不满足上面的情况,则意味着我们该推导此题的正解了
首先,如果这个序列的前一部分为递减,则这一部分不能再改大了。所以,我们要枚举到第一个不符合递减的位置,找到后再把后面一部分改大一丢丢
【找到这个位置后,在它后面找到最小的大于它的,交换。然后,再将后面那部分排序】
STEP3
LJS大佬提议叫我模拟一遍,我们再来举个栗子
65816525125971
首先,我们还是先排除一开始递减的部分,将后面半截拎出来
816525125971
在 8 后面找到最小的个大于它的,交换
916525125871
排序后
911122555678
所以答案就是
65911122555678
简单吗【???】
AC代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 1005;
int a[MAXN];
char s[MAXN];
int main() {
int t;
scanf("%d", &t);
while (t--) {
int k;
scanf("%d %s", &k, s + 1);
int n = strlen(s + 1);
for (int i = 1; i <= n; i++) a[i] = s[i] - '0';
if (n == 1) {
printf("%d BIGGEST\n", k);
continue;
}
bool flag = false;
for (int i = n - 1; i >= 1; i--) {
if (a[i] < a[i + 1]) {
flag = true;
int v = 1, mi = 10;
for (int j = i + 1; j <= n; j++) {
if (a[i] < a[j] && a[j] < mi) {
mi = a[j];
v = j;
}
}
swap(a[i], a[v]);
sort(a + i + 1, a + n + 1);
break;
}
}
if (flag == false) {
printf("%d BIGGEST\n", k);
continue;
} else {
printf("%d ", k);
for (int i = 1; i <= n; i++) printf("%d", a[i]);
}
printf("\n");
}
return 0;
}