AtCoder[AGC010E] Rearranging
题目描述
有两人 \(A,B\),给定一个长度为 \(n\) 的序列 \(a\),有以下两个操作:
- \(A\) 将该序列任意排列;
- \(B\) 可以将任意两个互质的数交换位置。
\(A\) 希望最后序列字典序尽可能小,\(B\) 希望最后序列字典序尽可能大,请你输出最后序列。
数据范围:\(n\le 2\times 10^3\),\(a_i\le 10^8\)。
时间范围:\(2000\operatorname{ms}\)。
Solution
可以发现,对于任意两个不互质的数,他们的相对位置不会改变。
因此可以建出一张图,将任意两个不互质的数连边。
由于 \(A\) 要使字典序最小,所以 \(A\) 应该把较小的数放左边。
因此可以建出有向边然后拓扑排序。
\(B\) 要使字典序最大,可以在拓扑排序的时候优先队列维护。
时间复杂度为 \(O(n^2\log n)\)。
Code
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=2020;
int Fir[maxn],Nxt[maxn*maxn],Too[maxn*maxn],rd[maxn],tot;
bool G[maxn][maxn],vis[maxn];
int n,a[maxn];
priority_queue<int> Q;
inline int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
inline void add(int a,int b){
Too[++tot]=b;Nxt[tot]=Fir[a];Fir[a]=tot;++rd[b];
}
inline void dfs(int u){
vis[u]=1;
for(int v=1;v<=n;++v)
if(!vis[v]&&G[u][v]){
add(u,v);
dfs(v);
}
}
inline void topsort(){
for(int i=1;i<=n;++i)
if(!rd[i])Q.push(i);
while(!Q.empty()){
int u=Q.top();Q.pop();
printf("%d ",a[u]);
for(int i=Fir[u];i;i=Nxt[i]){
int v=Too[i];
if(!--rd[v])Q.push(v);
}
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%d",&a[i]);
sort(a+1,a+n+1);
for(int i=1;i<=n;++i)
for(int j=i+1;j<=n;++j)
if(gcd(a[i],a[j])!=1)
G[i][j]=G[j][i]=1;
for(int i=1;i<=n;++i)
if(!vis[i])
dfs(i);
topsort();
return 0;
}

浙公网安备 33010602011771号