hiho187
每天补补题。。。。
题目1 : 分隔相同整数
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
给定一个包含N个整数的数组A。你的任务是将A重新排列,使得任意两个相等的整数在数组中都不相邻。
如果存在多个重排后的数组满足条件,输出字典序最小的数组。
这里字典序最小指:首先尽量使第一个整数最小,其次使第二个整数最小,以此类推。
输入
第一行包含一个整数N,表示数组的长度。(1 <= N <= 100000)
第二行包含N个整数,依次是 A1, A2, … AN。(1 <= Ai <= 1000000000)
输出
输出字典序最小的重排数组。如果这样的数组不存在,输出-1。
样例输入
4
2 1 3 3
样例输出
1 3 2 3
思路 贪心
- 首先可以发现无解的条件: 当某个数字出现的次数超过
的时候不能满足条件。
1) 预处理 ,生成二元组集合 。表示 有 个, 有 个……, 有 个。
2) 找出c值最大的二元组 。如果 过多,即 ,则无解。
3) 依次找出重排后的第一个数、第二个数……第N个数:
3.1) 找出c值最大的二元组 ,如果ci恰好满足: 。那么当前数字只能选择 。
3.2) 如果 ,找出a值最小的二元组 。如果前一个数字选的不是 ,那么选择 。
3.3) 如果前一个数字选的就是 ,再找出a值次小的二元组 。选择 。
不论上述哪种情况,假设最后选择的是 ,都要 。特别的如果 ,则要将 从S中删除。
#include <iostream>
#include <map>
#include <set>
using namespace std;
const int N = 1e5+5;
int a[N];
int main()
{
int n;
cin>>n;
map<int,int>cnt;
set<pair<int,int> > S;
for (int i = 0; i < n; ++i) {
cin>>a[i];
cnt[a[i]]++;
}
for (map<int,int>::iterator it = cnt.begin(); it != cnt.end(); ++it) {
S.insert(make_pair(it->second,it->first));
}
if ((--S.end())->first * 2 - 1 > n) {
cout << "-1" << endl;
return 0;
}
int pre = -1;
for ( int i = 1; i <= n; ++i) {
int x;
if ((--S.end())->first * 2 - 1 == (n + 1 - i)) {
x = (--S.end())->second;
}
else{
map<int,int>::iterator it = cnt.begin();
if (it->first == pre) ++it;
x = it->first;
}
S.erase(make_pair(cnt[x],x));
if (--cnt[x] > 0) {
S.insert(make_pair(cnt[x],x));
}
else
cnt.erase(x);
cout << x << " ";
pre = x;
}
cout << endl;
return 0;
}