Permutations
题面翻译
题目描述
“排列”是指一个长度为n的序列,且其中1到n的每个数刚好出现一次。例如,(1) (4,3,5,1,2) (3,2,1)都是排列,而(1,1) (4,3,1) (2,3,4)则不是。
假设某人拿了几个排列(长度不一定相同),把它们连在一起写成了一个数列,并将这个数列打乱顺序。你的任务是将这个数列重新组成原来的几个排列(如果可能的话)。
输入输出格式
输入格式:
第1行是一个整数n(1<=n<=105)。下一行是这个打乱后的n个整数,用一个空格隔开。这个数列中的数在1到105的范围内。
输出格式:
如果这个数列能被分成若干的排列,且数列中的每个数恰好属于一个排列,请在第1行输出排列的个数。第2行有n个数,对应着给定数列的n个数:如果第i个元素属于第1个排列,输出的这一行的第i个数就是1,如果它属于第2个排列,那么它对应的输出中的数就是2,等等。这些排列的顺序无关紧要。
如果有多种答案,输出其中任意一个。如果没有答案,在第1行输出-1.
说明
在第1个样例中数组被分成了三个排列:(2,1) (3,2,1,4,5) (1,2)。第1个排列由原数列的第2和4个数组成,第2个排列由第3、5、6、7、9个元素组成,第3个排列由第1和8个元素组成。显然,还有另外几种分组的方式。
题目描述
A permutation is a sequence of integers from 1 1 1to n n nof length n n ncontaining each number exactly once. For example, ( 1 ) (1) (1), ( 4 , 3 , 5 , 1 , 2 ) (4,3,5,1,2) (4,3,5,1,2), ( 3 , 2 , 1 ) (3,2,1) (3,2,1)are permutations, and ( 1 , 1 ) (1,1) (1,1), ( 4 , 3 , 1 ) (4,3,1) (4,3,1), ( 2 , 3 , 4 ) (2,3,4) (2,3,4)are not.
There are many tasks on permutations. Today you are going to solve one of them. Let’s imagine that somebody took several permutations (perhaps, with a different number of elements), wrote them down consecutively as one array and then shuffled the resulting array. The task is to restore the initial permutations if it is possible.
输入格式
The first line contains an integer n n n( 1 < = n < = 1 0 5 1<=n<=10^{5} 1<=n<=105). The next line contains the mixed array of n n nintegers, divided with a single space. The numbers in the array are from 1 1 1to 1 0 5 10^{5} 105.
输出格式
If this array can be split into several permutations so that every element of the array belongs to exactly one permutation, print in the first line the number of permutations. The second line should contain n n nnumbers, corresponding to the elements of the given array. If the i i i-th element belongs to the first permutation, the i i i-th number should be 1 1 1, if it belongs to the second one, then its number should be 2 2 2and so on. The order of the permutations’ numbering is free.
If several solutions are possible, print any one of them. If there’s no solution, print in the first line − 1 -1 −1.
样例 #1
样例输入 #1
9
1 2 3 1 2 1 4 2 5
样例输出 #1
3
3 1 2 1 2 2 2 3 2
样例 #2
样例输入 #2
4
4 3 2 1
样例输出 #2
1
1 1 1 1
样例 #3
样例输入 #3
4
1 2 2 3
样例输出 #3
-1
提示
In the first sample test the array is split into three permutations: ( 2 , 1 ) (2,1) (2,1), ( 3 , 2 , 1 , 4 , 5 ) (3,2,1,4,5) (3,2,1,4,5), ( 1 , 2 ) (1,2) (1,2). The first permutation is formed by the second and the fourth elements of the array, the second one — by the third, the fifth, the sixth, the seventh and the ninth elements, the third one — by the first and the eigth elements. Clearly, there are other splitting variants possible.
思路:
这题首先要判断输入的数列能否被分成完整的若干的排列,如果不行,就直接输出-1结束,如果可以的话,先输出可以分成的个数,然后输出给定的各个数属于第几个排列里,只要输出其中一种。
首先解决第一个问题,先使用数组存入各个数,因为我打算使用sort排序来进行判断,所以会打乱顺序,所以得开一个新数组存相同的数据。sort排序后第一个数一定是1,且排序后的相邻的数不能相差1,然后数字越大的数出现次数不能比数字小的多,不然输出-1
如果可以分成的话,要输出各个数属于第几个个排列,可以使用map来记录出现次数,以原来的顺序遍历输出map中键的值,每输出一次键的值减1即可输出题目要求的顺序
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
// 创建一个大小为 n 的整数向量 v 和 g
vector<int> v(n), g(n);
// 创建一个 map,用于记录每个元素在原序列中的出现次数
map<int, int> mp;
// 读取输入的整数序列,并同时更新 g 和 mp
for (int i = 0; i < n; i++) {
cin >> v[i];
g[i] = v[i];
mp[g[i]]++;
}
// 对 v 进行排序,用于后续判断是否可以分成连续子序列
sort(v.begin(), v.end());
// 如果排序后的序列的最小值不为 1,则无法分成连续子序列
if (v[0] != 1) {
cout << "-1\n";
return 0;
}
int a = 0, b = mp[1];
for (int i = 0; i < n; i++) {
// 如果当前元素与前一个元素之差大于 1,则无法分成连续子序列
if (i > 0 && v[i] - v[i - 1] > 1) {
cout << "-1\n";
return 0;
}
// 更新 a 和 b,用于判断当前子序列中相同元素的个数是否超过其在原序列中的出现次数
if (i == 0) {
a = 1;
} else if (v[i] == v[i - 1]) {
a++;
} else {
if (a > b) {
cout << "-1\n";
return 0;
}
b = a;
a = 1;
}
}
// 输出最大出现次数,并按照原序列的顺序输出各个元素的出现次数
cout << mp[v[0]] << '\n';
for (int i = 0; i < n; i++) {
if (i == 0) {
cout << mp[g[i]];
} else {
cout << ' ' << mp[g[i]];
}
mp[g[i]]--;
}
return 0;
}