专栏文章

题解:CF2056B Find the Permutation

CF2056B题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miqh0ih8
此快照首次捕获于
2025/12/04 04:39
3 个月前
此快照最后确认于
2025/12/04 04:39
3 个月前
查看原文

简要说明题意:

有一个 11nn 的全排列 pp,现在对所有的 1i<jn,pi<pj1 \leq i<j \leq n,p_i<p_j,连一条 i,ji,j 的无向边得到无向图
给出图求原排列 pp

题目分析:

我们可以想一下 1i<jn,pi<pj1 \leq i<j \leq n,p_i<p_j 这个连边条件,它的意思是:每个数都要与更大且在右侧的数连边。
所有更大且在右侧的数都会被连边,并且所有更大且在左侧的数不会连边。
也就是说,可以通过每个数和更大的数的连接情况,得到每个数与更大的数的左右关系。
只要对所有的数都这么操作,我们可以得到所有数的左右关系(因为任意两个不相等的数都可以比出大小)。
根据所有数的左右关系还原原序列顺序,这个问题是拓扑排序板子。读入,建图和拓扑排序都是 O(n2)O(\sum n^2)
代码如下:
CPP
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
string s;
bool map_[1001][1001];
int v[1001],last_[1001],next_[1000001],from_[1000001],to_[1000001],d[1001],cnt;
void link(int x,int y){
    from_[cnt]=x,to_[cnt]=y,next_[cnt]=last_[x],last_[x]=cnt++;
}
queue<int> q;
void toposort(int n){
    while(!q.empty()) q.pop();
    for(int i=1;i<=n;++i) if(!d[i]) q.push(i);
    int now,tot=0;
    while(!q.empty()){
        now=q.front(),q.pop(),v[tot++]=now;
        for(int i=last_[now];~i;i=next_[i]){
            --d[to_[i]];
            if(!d[to_[i]]) q.push(to_[i]);
        }
    }
}
int main(){
    int T,n;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n),fill(last_+1,last_+1+n,-1),fill(d+1,d+1+n,0),cnt=0;
        for(int i=1;i<=n;++i){
            cin>>s;
            for(int j=0;j<n;++j) map_[i][j+1]=(s[j]^'0');
        }
        for(int i=1;i<=n;++i) for(int j=i+1;j<=n;++j) map_[i][j]?(link(i,j),++d[j]):(link(j,i),++d[i]);
        toposort(n);
        for(int i=0;i<n;++i) printf("%d ",v[i]);
        putchar('\n');
    }
    return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...