Codeforces Round #671 (Div. 2) E. Decryption

E. Decryption
Description

An agent called Cypher is decrypting a message, that contains a composite number n. All divisors of n, which are greater than 1, are placed in a circle. Cypher can choose the initial order of numbers in the circle.

In one move Cypher can choose two adjacent numbers in a circle and insert their least common multiple between them. He can do that move as many times as needed.

A message is decrypted, if every two adjacent numbers are not coprime. Note that for such constraints it’s always possible to decrypt the message.

Find the minimal number of moves that Cypher should do to decrypt the message, and show the initial order of numbers in the circle for that.

Input

The first line contains an integer t (1≤t≤100) — the number of test cases. Next t lines describe each test case.

In a single line of each test case description, there is a single composite number n (4≤n≤109) — the number from the message.

It’s guaranteed that the total number of divisors of n for all test cases does not exceed 2⋅105.

Output

For each test case in the first line output the initial order of divisors, which are greater than 1, in the circle. In the second line output, the minimal number of moves needed to decrypt the message.

If there are different possible orders with a correct answer, print any of them.

Example
input
3
6
4
30
output
2 3 6 
1
2 4 
0
2 30 6 3 15 5 10 
0

Note
In the first test case 6 has three divisors, which are greater than 1: 2,3,6. Regardless of the initial order, numbers 2 and 3 are adjacent, so it’s needed to place their least common multiple between them. After that the circle becomes 2,6,3,6, and every two adjacent numbers are not coprime.

In the second test case 4 has two divisors greater than 1: 2,4, and they are not coprime, so any initial order is correct, and it’s not needed to place any least common multiples.

In the third test case all divisors of 30 greater than 1 can be placed in some order so that there are no two adjacent numbers that are coprime.

题意: 第一行输入测试案例的个数,接下来 t 行每行输入一个数。求这个数的所有因子的不互质的排列顺序。

题解: 见代码。

c++ AC 代码

#include <map>
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <algorithm>
using namespace std;

const int maxn = 1e5 + 10;

int a[maxn], v[maxn], cnt;

void getprime()		// 欧拉筛法质数打表
{
	for (int i = 2; i <= maxn; i++)
	{
		if (!v[i])
			a[++cnt] = i;
		for (int j = 1; j <= cnt && 1ll * i * a[j] < maxn; j++)
		{
			v[i * a[j]] = 1;
			if (!(i % a[j]))
				break;
		}
	}
}

int main()
{
	getprime();		// 先获取质数
	int t;
	scanf("%d", &t);
	while (t--)
	{
		int n;
		scanf("%d", &n);
		map<int, int> mp;	// 记录书否是否已经输出过了
		vector<int> prime;	// 获取该数所有因子中的的具有公共质数的因子的最小质数
		vector<int> div;	// 获取因子

		for (int i = 2; i <= sqrt(n); i++)		// 求因子
		{
			if (n % i == 0)
			{
				div.push_back(i);
				if (n / i != i)
					div.push_back(n / i);
			}
		}

		div.push_back(n);
		sort(div.begin(), div.end());	// 从小到大排序

		int tmp = n;
		for (int i = 1; i <= cnt; i++)	// 找出所有约数中的质数
		{
			if (a[i] > tmp)
				break;
			if (!(tmp % a[i]))
			{
				prime.push_back(a[i]);
				while (!(tmp % a[i]))
					tmp /= a[i];
			}
		}

		if (tmp > 1)
			prime.push_back(tmp);

		sort(prime.begin(), prime.end());	// 将这些质数从小到大排序

		if (prime.size() == 1)		// 如果它所有约数中只有一个质因子,那直接输出这个数的所有因子
		{
			for (int i = 0; i < div.size(); i++)
				printf("%d ", div[i]);
			puts("\n0");
		}
		else if (prime.size() == 2 && div.size() == 3)	// 如果有2个质因子,并且它的总因子数量为3,无论如何排列,
		{												// 他们直接的不互质的对数最多只有2对所以直接输出
			for (int i = 0; i < div.size(); i++)
				printf("%d ", div[i]);
			puts("\n1");
		}
		else	// 其他情况(题目示例中的数字为30的情况)
		{
			vector<int> now;
			for (int i = 0; i < prime.size(); i++)		// 找出所有因子中能够整除它的质数的因子
			{
				int d1 = prime[i], d2 = prime[(i + 1) % prime.size()];
				for (int j = 0; j < div.size(); j++)
				{
					if (!mp[div[j]] && div[j] % d1 == 0 && div[j] % d2 == 0)	// 该因子既能被d1整除也能被d2整除
					{															// 该因子可以放在d1、d2之间,与d1、d2构成两对不互质对
						now.push_back(div[j]);			// 在示例中是6、15、10
						mp[div[j]] = 1;
						break;
					}
				}
			}
			for (int i = 0; i < prime.size(); i++)		// 按顺序输出
			{
				for (int j = 0; j < div.size(); j++)
				{
					if (!mp[div[j]] && div[j] % prime[i] == 0)
					{
						printf("%d ", div[j]);
						mp[div[j]] = 1;
					}
				}
				printf("%d ", now[i]);
			}
			puts("\n0");
		}
	}
	// system("pause");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值