牛客网多校4 Hash Function(拓扑排序)

感觉自己很恍惚,真的是越来越菜了。

题目:给一个哈希表,判断哈希表是不是合法,合法的话求一个字典序最小的插入序列,不合法输出-1

思路:建图好困难,比赛时自己建图乱七八糟,赛后看了大佬的代码才最终完成自己的。题解是线段树建图...emm没用过。

记录一个movl[i]表示这个点可以往前移动的合法步数,过程中找前面的可行点连边,movl路径压缩。总共连边数最多最多也是不会超过2n的,O(n)建图。

#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
struct node1
{
    int v,next;
};
node1 edge[2*maxn];
struct node2
{
    bool friend operator < (node2 n1,node2 n2){
        return n1.val>n2.val;
    }
    int id,val;
};
priority_queue<node2> que;
int ary[maxn],first[maxn],degree[maxn];
int ans[maxn];
int tot;
void addedge(int u,int v)
{
    edge[tot].v=v;
    edge[tot].next=first[u];
    first[u]=tot++;
}
int n,nu;
void toposort()
{
    node2 cur,tmp;
    while(!que.empty()) que.pop();
    int num=0,i,u,v;
    for(i=0;i<n;i++)
    if(degree[i]==0&&ary[i]!=-1)
    {
        tmp.id=i,tmp.val=ary[i];
        que.push(tmp);
    }
    while(!que.empty())
    {
        cur=que.top();
        que.pop();
        ans[num++]=cur.val;
        u=cur.id;
        for(i=first[u];i!=-1;i=edge[i].next)
        {
            v=edge[i].v;
            degree[v]--;
            if(degree[v]==0&&ary[v]!=-1)
            {
                tmp.id=v,tmp.val=ary[v];
                que.push(tmp);
            }
        }
    }
    if(num!=nu) puts("-1");//散列表不合法
    else//num==0时只输出一个换行
    {
        for(i=0;i<num;i++)
        {
            printf("%d",ans[i]);
            if(i<num-1) printf(" ");
        }
        puts("");
    }
}
int t;
int movl[maxn];
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        nu=0;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%d",&ary[i]);
            if(ary[i]!=-1) nu++;
            movl[i]=1;
        }
        tot=0;
        memset(first,-1,sizeof first);
        memset(degree,0,sizeof degree);
        int flag=1;
        for(int i=0;i<n;i++)
        {
            if(ary[i]==-1) continue;
            if(ary[i]%n==i) continue;//这个点就在自己该在的位置
            int k=ary[i]%n;//本该在k这个位置的
            int j=(i-1+n)%n;//前一个位置
            while(1)
            {
                if(ary[j]==-1)//在没到达该放位置前遇到了-1,说明散列表是不合法的
                {
                    flag=0;
                    break;
                }
                addedge(j,i);
                degree[i]++;
                movl[i]+=movl[j];//相当于压缩路径了
                int dis=(i-k+n)%n;//距离本来该放位置的距离
                if(dis>=movl[i])
                    j=(j-movl[j]+n)%n;//j往前移
                else break;
            }
            if(!flag) break;
        }
        if(flag)
            toposort();//拓扑排序
        else puts("-1");
    }
    return 0;
}
/*
100
9
16 -1 -1 -1 -1 -1 -1 7 8

4
8 5 2 3

10
8 10 -1 -1 34 75 86 55 88 18

2
1 2

5
100000 1000000000 111 1154 1123
*/

猜你喜欢

转载自blog.csdn.net/dllpxfire/article/details/81265300