[agc010e]Rearranging

前言

想到了相对顺序和连图。
想到了多个合并。
似乎没想到按照大小连出拓扑图,导致不知道怎么样才是最小不可操作的。

题目大意

一个长度为n的序列。
先手可以任意打乱,然后后手可以执行若干次以下操作:交换两个相邻且互质的数。
先手希望字典序最小,后手希望字典序最大,最后序列会变成啥样?

做法

容易发现对于不互质的一对数,相对位置永远不变。
我们让不互质的数之间连一条边,这样形成了图。
我们不妨从小到大对于每个点开始dfs其所在联通块,按照连向点的权值从小到大优先遍历,可以变成一个有向无环图。
容易发现我们只要做一个每次选一个最大的权值的拓扑排序,就是答案。

#include<cstdio>
#include<algorithm>
#include<queue>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=2000+10;
struct dong{
    int x,y;
    friend bool operator <(dong a,dong b){
        return a.x<b.x;
    }
} zlt;
priority_queue<dong> dl;
bool bz[maxn][maxn],pd[maxn];
int a[maxn],d[maxn];
int h[maxn],go[maxn*maxn],nxt[maxn*maxn];
int i,j,k,l,t,n,m,tot,now;
int gcd(int a,int b){
    return b?gcd(b,a%b):a;
}
void add(int x,int y){
    d[y]++;
    go[++tot]=y;
    nxt[tot]=h[x];
    h[x]=tot;
}
void dfs(int x){
    pd[x]=1;
    int i;
    fo(i,1,n)
        if (bz[x][i]&&!pd[i]){
            add(x,i);
            dfs(i);
        }
}
int main(){
    scanf("%d",&n);
    fo(i,1,n) scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    fo(i,1,n-1)
        fo(j,i+1,n)
            if (gcd(a[i],a[j])>1) bz[i][j]=bz[j][i]=1;
    fo(i,1,n)
        if (!pd[i]) dfs(i);
    fo(i,1,n)
        if (!d[i]){
            zlt.x=a[i];
            zlt.y=i;
            dl.push(zlt);
        }
    fo(i,1,n){
        zlt=dl.top();
        dl.pop();
        now=zlt.y;
        printf("%d ",a[now]);
        t=h[now];
        while (t){
            d[go[t]]--;
            if (!d[go[t]]){
                zlt.x=a[go[t]];
                zlt.y=go[t];
                dl.push(zlt);
            }
            t=nxt[t];
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值