题意:
给出1-n的数字,让选择m对数字,让gcd(a_i,b_i)>1,让m尽可能大,并且输出这m对对应的数字。
思路:
整体的思路就是筛法+贪心。
不过我代码写的比较复杂,比较low。。
首先就是筛法,把n个数的质因子种类数,和最小质因数维护出来。cnt[i]表示i的质因子有多少种,mi[i]表示i的最小质因数是多少
开一个vector 其中z[i]表示含有质因子i的数字的集合。
然后我们去进行两个数字的匹配,这里去贪心的选择。
首先我们应该倒序 即从z[n]到z[1]里面去选择。为什么? 因为含有的质因子越大,可以匹配到的另一个的个数越少,所以优先倒序来。
对于具体到某个z[i] 这里还需要一次贪心,比如 z[2][0]=2,z[2][1]=6,z[2][2]=8,z[2][3]=10 对z[2]排序应该是这样的 2 8 10 6
对于一个数的质因子的种类越多,能匹配的个数也越多,所以对于具体的z[i] 应该先按照质因子种类数从小到大排序,对于质因子种类数相同的,最小质因数越大,我们就优先对他进行匹配。
总体复杂度O(T * nlogn)
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
#define int long long
bool vis[maxn];
vector<int> z[maxn],qq;
int cnt[maxn],mi[maxn];
bool cmp(int x,int y){
if(cnt[x]==cnt[y]) return mi[x]>mi[y];
return cnt[x]<cnt[y];
}
signed main()
{
int t;cin>>t;
while(t--)
{
int n;
cin>>n;
qq.clear();
for(int i=1; i<=n; i++)
vis[i]=0,z[i].clear(),cnt[i]=0,mi[i]=1e9;
for(int i=2;i<=n;i++){
if(!vis[i]){
for(int j=i;j<=n;j+=i){
vis[j]=1;
mi[j]=min(mi[j],i);
cnt[j]++;
z[i].push_back(j);
}
}
}
for(int i=1;i<=n;i++) vis[i]=0;
int ans=0;
for(int i=n; i; i--)
{
sort(z[i].begin(),z[i].end(),cmp);
int a=-1,b=-1;
for(int j=0; j<z[i].size(); j++)
{
if(!vis[z[i][j]])
{
if(a==-1)
{
a=z[i][j];
}
else if(b==-1)
{
b=z[i][j];
}
}
if(a!=-1 && b!=-1)
{
qq.push_back(a);
qq.push_back(b);
ans++;
vis[a]=vis[b]=1;
a=b=-1;
}
}
}
cout<<ans<<endl;
for(int i=0; i<ans; ++i)
cout<<qq[2*i]<<" "<<qq[2*i+1]<<endl;
}
return 0;
}

京公网安备 11010502036488号