牛客网暑期ACM多校训练营(第四场)J (类似拓扑排序)

版权声明:欢迎复制!!! https://blog.csdn.net/qq_37493070/article/details/82114340

题目链接 : 点此传送

题意 :

T组测试样例,给你n个 用 val[i]%n(相同则后移) 哈希过的数组,让你还原成字典序最小的原数组

思路

建个优先队列每次都取最小的看能不能放,首先把所有直接能放入的点全部入队(就是 v[i]%n==i的),然后依次挑最小的往后填下一个数字,主要判断在i放入后 i+1 是否也能放入,看了大佬博客有两种简单方法,感觉比给的题解简单,他们都是判断v[i]%n 到 i所在位置之间是否全部填上,因为他是哈希是相同后移一位,后面那个填上的时候v[i]%n 到 i-1 肯定已经全部填上
1. 每次寻找他后面最近没有放入的点r,和前面最近没有放入的点 l, r与l之间的距离肯定会大于等于 r到 v[r]%n之间的距离,否则中间有空缺
2. 用并查集维护判断是否连续,每次加入一个点,都把他和他的下一位相连接,如果 v[i]%n到 i 之间有没填的,那么这条链就是从中间断开的,这时候 find(v[i]%n)!=i,也就不满足

代码(方法一)
#include<bits/stdc++.h>
using namespace std;
const long long maxn=2e5+7;
int v[maxn];
int vis[maxn];
int use[maxn];
int pal[maxn];
int nex[maxn];
int pre[maxn];
int main(){

    int t;
    scanf("%d",&t);
    while(t--){

        long long n;
        scanf("%lld",&n);
        for(int i=0;i<n;i++){
            scanf("%d",&v[i]); 
        }
        memset(vis,0,sizeof(vis));
        memset(use,0,sizeof(use));
        int cnt=0;
        priority_queue<pair<int,int>,vector<pair<int,int>> ,greater<pair<int,int> > >q;
        for(int i=0;i<n;i++){
            if(v[i]%n==i&&v[i]!=-1) {
                q.push(make_pair(v[i],i));
                use[i]=1;
            } 
            if(v[i]!=-1) cnt++; 
        }
        int ans=0;

        while(!q.empty()){

            pair<int,int> p=q.top();
            q.pop();
            int cs=p.second;
            vis[cs]=1;
            pal[ans++]=p.first;
            if(ans==cnt) break;
            int l=(cs-1+n)%n;
            int r=(cs+1)%n;
            while(vis[l]) l=pre[l];
            while (vis[r]) r=nex[r];
            nex[cs]=r;
            pre[cs]=l;
            if(v[r]!=-1&&!use[r]&&((r-l-1+n+n)%n>=(r-v[r]%n+n)%n)){
                q.push(make_pair(v[r],r));
                use[r]=1;
            }


        }
        if(ans!=cnt){
            printf("-1\n");
        }else{
            if(ans==0) puts("");
            else
            for(int i=0;i<ans;i++){
                printf("%d%c",pal[i],i==ans-1?'\n':' ');
            }

        }
    }


    return 0;

}
代码(方法二)

#include<bits/stdc++.h>
using namespace std;
const long long maxn=2e5+7;
int ss[maxn];
int v[maxn];
int pal[maxn];
int vis[maxn];
int find(int x){return x==ss[x]?x:ss[x]=find(ss[x]);}
void init(int n){for (int i=0;i<=n;i++)ss[i]=i,vis[i]=0;}
int main(){

    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        init(n);

        for(int i=0;i<n;i++){
            scanf("%d",&v[i]); 
        }
        priority_queue<pair<int,int>,vector<pair<int,int>> ,greater<pair<int,int>> >q;
        int cnt=0,ans=0;
        for(int i=0;i<n;i++){

            if(v[i]!=-1&&v[i]%n==i) q.push(make_pair(v[i],i)),vis[i]=1;
            if(v[i]!=-1) cnt++;

        } 

        while(!q.empty()){
            pair<int,int> p=q.top();
            q.pop();
            int cs=p.second;
            pal[ans++]=v[cs];
            if(ans==cnt) break;
            int nex=(cs+1)%n;
            ss[cs]=ss[nex];
            int k=find(cs);
            if(vis[k]|v[k]==-1) continue;
            if(find(v[k]%n)==k){
                q.push(make_pair(v[k],k));
                vis[k]=1;
            }
        }
        if(ans!=cnt){
            printf("-1\n");
        }else{
            if(ans==0) puts("");
            else
            for(int i=0;i<ans;i++){
                printf("%d%c",pal[i],i==ans-1?'\n':' ');
            }

        }

    }




    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37493070/article/details/82114340