hiho187 分隔相同整数

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. 首先可以发现无解的条件: 当某个数字出现的次数超过 (N+1)/2 ( N + 1 ) / 2 的时候不能满足条件。
    1) 预处理 A1 AN A 1   A N ,生成二元组集合 S=(a1,c1),(a2,c2),(am,cm) S = ( a 1 , c 1 ) , ( a 2 , c 2 ) , ⋯ ( a m , c m ) 。表示 a1 a 1 c1 c 1 个, a2 a 2 c2 c 2 个……, am a m cm c m 个。

2) 找出c值最大的二元组 (ai,ci) ( a i , c i ) 。如果 ci c i 过多,即 ci+ci1>n c i + c i − 1 > n ,则无解。

3) 依次找出重排后的第一个数、第二个数……第N个数:

3.1) 找出c值最大的二元组 (ai,ci) ( a i , c i ) ,如果ci恰好满足: ci+ci1==n c i + c i − 1 == n 。那么当前数字只能选择 ai a i

3.2) 如果 ci+ci1<n c i + c i − 1 < n ,找出a值最小的二元组 (ai,ci) ( a i , c i ) 。如果前一个数字选的不是 aj a j ,那么选择 aj a j

3.3) 如果前一个数字选的就是 aj a j ,再找出a值次小的二元组 (ak,ck) ( a k , c k ) 。选择 ak a k

不论上述哪种情况,假设最后选择的是 (at,ct) ( a t , c t ) ,都要 ct=1 c t − = 1 。特别的如果 ct=0 c t = 0 ,则要将 (at,ct) ( a t , c t ) 从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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值