火星人.题解

题目简述

与水星人一样,火星人也用数字排列代表要表示的数字,如最多使用5个数字情况下,使用 { 1 , 2 , 3 , 4 , 5 } \{1, 2, 3, 4, 5\} {1,2,3,4,5}表示1, { 1 , 2 , 3 , 5 , 4 } \{1, 2, 3, 5, 4\} {1,2,3,5,4}表示2,……, { 5 , 4 , 3 , 2 , 1 } \{5, 4, 3, 2, 1\} {5,4,3,2,1}表示120。
现给定一个火星人的数字序列,以及一个需要加上的小整数,然后将其转化为火星人的数字表示形式。

输入

N:表示最多使用N位数字,其中 0 < N ≤ 1 0 6 0 < N \leq 10^6 0<N106;
M:表示需要加上的值,其中 0 < M < 1 0 6 0 < M < 10^6 0<M<106;
以及N个数字组成的数字序列。

输出

一个数字序列。

思路

数据范围

由于N的最大取值不超过 1 0 6 10^6 106,显然,不可能直接计算 N ! N! N!

解题思路

由于不能采用“水星人”的解题思路,则考虑计算一个数字序列的下一个序列,相当于就是在当前数字序列基础上+1。如果需要在某个数字序列上+M,则循环计算M次下一个序列就能处理。

计算一个序列的下一个序列

下标 1 2 3 4
当前序列 2 4 3 1
交换项 1 0 0 0
后项排序 1 3 4
第1个大于交换项 0 1
交换 3 1 2 4

所以,序列 { 2 , 4 , 3 , 1 } \{2, 4, 3, 1\} {2,4,3,1}的下一序列为 { 3 , 1 , 2 , 4 } \{3, 1, 2, 4\} {3,1,2,4}

AC代码

#include 
#include 
using namespace std;
int bits[1000005];
// 交换两个整数
void swap(int * a, int * b) {
	int tmp = *a;
	*a = *b;
	*b = tmp;
}
// 输出当前序列
void output(int n) {
	for (int i = 1; i <= n; i++) {
		printf("%d ", bits[i]);
	}
	printf("\n");
}

int main() {
	int N;
	int M;	
	scanf("%d%d", &N, &M);	
	// 输入指定序列
	for (int i = 1; i <= N; i++) {
		scanf("%d", &bits[i]);
	}	
	// 寻找M次下一序列
	while (M) {
		// 查找需要修改的数字下标
		int swap_index = N - 1; 
		while (bits[swap_index] > bits[swap_index + 1]) {
			swap_index--;
		}
		// 将待修改数字下标后面的所有数字排序
		sort(bits + swap_index + 1, bits + N + 1);
		// 查找待修数字后面序列中第一个更大的数字,并交换
		for (int i = swap_index + 1; i <= N; i++) {
			if (bits[i] > bits[swap_index]) {
				swap(&bits[swap_index], &bits[i]);
				break;
			}
		}
		//output(N);
		M--;
	} 
	output(N);	
	return 0;
} 

你可能感兴趣的:(ACM/OI题解,算法)