C - Array in the Pocket (ZOJ - 4102)

C - Array in the Pocket (ZOJ - 4102)

题意:给你数组a,问你重新排列这个数组得到b,能使a[i]!=b[i]字典序最小的b数组。
思路:贪心其实可以做!!!

3 2 1 5 4 4 4 4 7

手动模拟这个例子,很快可以得出

3 2 1 5 4 4 4 4 7
1 3 2 4 5 7 x x x

我们发现此时只有4能填,但是这个位置又不能填4,那么就得找一个位置去填这个4,很明显,在这个位置之前的我们按照贪心思路填的是最优的,没有到万不得已绝对不会去改变它,所以我们找此刻位置之后的能填4的,序列变成

3 2 1 5 4 4 4 4 7
1 3 2 4 5 7 x x 4

此时都后面能填的都填了,没有办法了,已经到了万不得已的情况了,就只能动前面的了,贪心的想,肯定是动越靠后越优,并且此时上方和下方都不能是4。所以我们可以取3 2来填,并且这个3 2应该按字典序最小的填(不按字典序也可以,往下看就知道了)。 序列变成

3 2 1 5 4 4 4 4 7
1 4 4 4 5 7 2 3 4

这种情况满足了条件,但并没有满足最小,此时对于4这些位置我们并不是按贪心思路填下去的,所以应该再把4的这些位置重排序一下,序列变成

3 2 1 5 4 4 4 4 7
1 4 4 4 2 3 5 7 4

这便是最优解。
复杂度O(k * n * log(n))

/*
▄███████▀▀▀▀▀▀███████▄
░▐████▀▒▒▒▒▒▒▒▒▒▒▀██████▄
░███▀▒▒▒ACCEPTED▒▒▒▒▀█████
░▐██▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████▌
░▐█▌▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████▌
░░█▒▄▀▀▀▀▀▄▒▒▄▀▀▀▀▀▄▒▐███▌
░░░▐░░░▄▄░░▌▐░░░▄▄░░▌▐███▌
░▄▀▌░░░▀▀░░▌▐░░░▀▀░░▌▒▀▒█▌
░▌▒▀▄░░░░▄▀▒▒▀▄░░░▄▀▒▒▄▀▒▌
░▀▄▐▒▀▀▀▀▒▒▒▒▒▒▀▀▀▒▒▒▒▒▒█
░░░▀▌▒▄██▄▄▄▄████▄▒▒▒▒█▀
░░░░▄██████████████▒▒▐▌
░░░▀███▀▀████▀█████▀▒▌
░░░░░▌▒▒▒▄▒▒▒▄▒▒▒▒▒▒▐
░░░░░▌▒▒▒▒▀▀▀▒▒▒▒▒▒▒▐

*/

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
const int INF=1e9+7;
const double eps=1e-6;
const long long mod=1e9+7;
typedef long long ll;
typedef pair<ll,ll>p;
int T,flag,n;
set<int>s;
int a[N],cnt[N],ans[N];
vector<int>pos[N],res[N];
int main() {
    
    
    cin>>T;
    while(T--) {
    
    
        flag=0,s.clear();
        scanf("%d",&n);
        for(int i=1; i<=n; i++)
            scanf("%d",&a[i]),cnt[i]=0,pos[i].clear(),res[i].clear(),ans[i]=0;
        for(int i=1; i<=n; i++) {
    
    
            cnt[a[i]]++;
            if(cnt[a[i]]>=n/2+1)
                flag=1;
            s.insert(a[i]);
        }
        if(flag) {
    
    
            printf("Impossible\n");
            continue;
        }
        for(int i=1; i<=n; i++) {
    
    
            auto val=*s.begin();
            if(s.size()==1&&val==a[i]) {
    
    ///把当前的数字分配给后面
                vector<int>poss,tmp;
                for(int j=i+1; j<=n; j++) {
    
    
                    if(a[j]!=val) {
    
    
                        ans[j]=val;
                        cnt[val]--;
                    }
                }
                for(int j=i; j<=n; j++) {
    
    ///后面有多少个不符合的位置
                    if(ans[j]==0&&a[j]==a[i])
                        poss.push_back(j);
                }
                for(int j=i-1; j>=1; j--) {
    
     ///从前面找符合的位置
                    if(cnt[val]==0)
                        break;
                    if(ans[j]!=val&&val!=a[j]) {
    
    
                        tmp.push_back(ans[j]);
                        ans[j]=val;
                        cnt[val]--;
                    }
                }
                int len=poss.size();
                for(int j=0; j<len; j++) {
    
    
                    ans[poss[j]]=tmp[j];
                }
                poss.clear(),tmp.clear();
                s.erase(val);
                 break;
            } else {
    
    
                auto it=s.begin();
                if(val==a[i]) {
    
    
                    ++it;
                }
                val=*it;
                ans[i]=val;
                //cout<<i<<" "<<val<<endl;
                cnt[val]--;
                if(cnt[val]==0)
                    s.erase(val);

            }
        }
        for(int i=1; i<=n; i++) {
    
    
            pos[a[i]].push_back(i);
            res[a[i]].push_back(ans[i]);
        }
        for(int i=1; i<=n; i++) {
    
    
            if(pos[i].size()==0)
                continue;
            sort(pos[i].begin(),pos[i].end());
            sort(res[i].begin(),res[i].end());
            int len=pos[i].size();
            for(int j=0; j<len; j++) {
    
    
                ans[pos[i][j]]=res[i][j];
            }
        }
        for(int i=1; i<=n; i++) {
    
    
            printf("%d%c",ans[i]," \n"[i==n]);
        }
    }
}
/*
1 9
3 2 1 5 4 4 4 4 7
*/

猜你喜欢

转载自blog.csdn.net/qq_43653111/article/details/105931804
今日推荐