[AGC010E] Rearranging

本文讲述了Takahashi和Aoki在黑板上的整数排列问题,Takahashi试图使最终序列尽可能小,Aoki则尽可能使其大。通过优化策略,文章探讨了如何通过交换互质的相邻数字来构建最大和最小的字典序序列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

There are $N$ integers written on a blackboard. The $i$-th integer is $A_i$.

Takahashi and Aoki will arrange these integers in a row, as follows:

  • First, Takahashi will arrange the integers as he wishes.
  • Then, Aoki will repeatedly swap two adjacent integers that are coprime, as many times as he wishes.

We will assume that Takahashi acts optimally so that the eventual sequence will be lexicographically as small as possible, and we will also assume that Aoki acts optimally so that the eventual sequence will be lexicographically as large as possible. Find the eventual sequence that will be produced.

Constraints

  • $1 ≦ N ≦ 2000$
  • $1 ≦ A_i ≦ 10^8$

Input

The input is given from Standard Input in the following format:

$N$
$A_1$ $A_2$ … $A_N$

Output

Print the eventual sequence that will be produced, in a line.


Sample Input 1

5
1 2 3 4 5

Sample Output 1

5 3 2 4 1

If Takahashi arranges the given integers in the order $(1,2,3,4,5)$, they will become $(5,3,2,4,1)$ after Aoki optimally manipulates them.


Sample Input 2

4
2 3 4 6

Sample Output 2

2 4 6 3

先把 \(a\) 排序。

给一个序列,如何判断另一个序列是否可以有其转换出来。

对于两个不互质的数 \(u,v\),他们在序列中的相对顺序不会改变。只要满足这个要求,排列就可以操作出来。

那么后手的最优策略就有了。建图然后用堆跑出字典序最大的拓扑序。

而先手就是要给出这个 DAG。建出图后,先手是要给一个无向图定向为 DAG,使得其字典序最大的拓扑序最小。

首先每个连通块是独立的。而且连通块中唯一的无入度的点一定是最小的那个点。现在在考虑一个点的所有出边怎么定向。

从小到大枚举出边,如果终点到达过,可以考虑下一个。否则就从这里深搜。为什么是深搜而不是广搜呢?因为有可能可以从某个点定向定回来这个出边。

#include<bits/stdc++.h>
using namespace std;
const int N=2005;
int n,a[N],p[N][N],in[N],vs[N];
priority_queue<int>q;
int gcd(int x,int y)
{
	if(!y)
		return x;
	return gcd(y,x%y);
}
void dfs(int x)
{
	vs[x]=1;
	for(int v=1;v<=n;v++)
	{
		if(!p[x][v])
			continue;
		if(vs[v])
			p[x][v]=p[v][x]=0;
		else
			p[v][x]=0,dfs(v);
	}
}
void topo()
{
	for(int i=1;i<=n;i++)
		if(!in[i])
			q.push(i);
	while(!q.empty())
	{
		int k=q.top();
		q.pop();
		printf("%d ",a[k]);
		for(int i=1;i<=n;i++)
		{
			if(p[k][i])
			{
				--in[i];
				if(!in[i])
					q.push(i);
			}
		}
	}
}
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=1;j<=n;j++)
			if(i^j&&gcd(a[i],a[j])^1)
				p[i][j]=p[j][i]=1;
	for(int i=1;i<=n;i++)
		if(!vs[i])
			dfs(i);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			if(p[i][j])
				in[j]++;
	topo();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值