2020牛客暑期多校训练营(第四场)——H

Harder Gcd Problem

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
Special Judge, 64bit IO Format: %lld

题目描述

After solving the Basic Gcd Problem, ZYB gives you a more difficult one:

Given an integer n{n}n, find two subset A{A}A and B{B}B of {1,2,…,n}{1,2,\dots,n}{1,2,…,n} such that:
​∣A∣=∣B∣=m{​|A|=|B|=m}​∣A∣=∣B∣=m and A∩B=∅A \cap B = \emptysetA∩B=∅
Let A={a1,a2,…,am}A={a_1,a_2,\dots,a_{m}}A={a1​,a2​,…,am​} and B={b1,b2,…,bm}B={b_1,b_2,\dots,b_m}B={b1​,b2​,…,bm​}, there exists two permutations p1,p2,…,pmp_1,p_2,\dots,p_mp1​,p2​,…,pm​ and q1,q2,…,qmq_1,q_2,\dots,q_mq1​,q2​,…,qm​ such that for each 1≤i≤m1 \le i \le m1≤i≤m, gcd⁡(api,bqi)>1\gcd(a_{p_i}, b_{q_i}) > 1gcd(api​​,bqi​​)>1.
Please find two subsets with maximum value of m{m}m.

输入描述:

There are multiple test cases. The first line of input contains an integer T{T}T, indicating the number of test cases.
For each test case, there is only one line containing an integer n{n}n (4≤n≤2×1054 \le n \le 2 \times 10^54≤n≤2×105)
It’s guaranteed that the sum of n{n}n of all test cases will not exceed 2×1052 \times 10^52×105.

输出描述:

For each test case, output an integer m{m}m in the first line. In the next m{m}m lines, each contains two integers aia_iai​ and bib_ibi​ (gcd⁡(ai,bi)>1\gcd(a_i, b_i) > 1gcd(ai​,bi​)>1), denoting the i{i}i-th element in subset A{A}A and B{B}B.
If there are multiple solutions, you can output any of them.

示例1

输入
复制
2
4
10
输出
复制
1
2 4
4
3 9
5 10
8 2
4 6

贪心问题没什么好说的

#include
using namespace std;
typedef long long ll;
const int N=1e6+500;
int f[N],vis[N],yz[N];
vector<int>q[N];
bool cmp(int x,int y) {
	if(yz[x]==yz[y])return f[x]>f[y];
	return yz[x]<yz[y];
}
int main() {
	int T;
	scanf("%d",&T);
	while(T--) {
		int n;
		scanf("%d",&n);
		for(int i=1; i<=n; ++i) {
			f[i]=0;
			vis[i]=0;
			yz[i]=0;
			q[i].clear();
		}
		for(int i=2; i<=n; ++i) {
			if(!f[i]) {
				for(int j=i; j<=n; j+=i) {
					if(!f[j])f[j]=i;
					yz[j]++;
					q[i].push_back(j);
				}
			}
		}
		int ans=0;
		vector<int>ans1;
		vector<int>ans2;
		for(int i=n/2; i>=2; --i) {
			sort(q[i].begin(),q[i].end(),cmp);
			int cut1=0,cut2=0;
			for(int j=0; j<q[i].size(); ++j) {
				if(!vis[q[i][j]]) {
					if(!cut1) {
						cut1=q[i][j];
					} else if(!cut2) {
						cut2=q[i][j];
					}
				}
				if(cut1&&cut2) {
					ans++;
					ans1.push_back(cut1);
					ans2.push_back(cut2);
					vis[cut1]++;
					vis[cut2]++;
					cut1=0;
					cut2=0;
				}
			}
		}
		printf("%d\n",ans);
		for(int i=0; i<ans; ++i) {
			printf("%d %d\n",ans1[i],ans2[i]);
		}
	}
	return 0;
}

你可能感兴趣的:(思维,数论与数学)