https://codeforces.com/problemset/problem/1176/D
题意翻译
从前有一个长度为nn的数组aa,其中每一个数都在22到2\cdot10^52⋅105之间,你不知道aa,但是你知道另一个长度为2n2n的数组bb,bb是由aa生成的。
生成方式如下:
首先,让bb等于aa。
然后,对于aa中的每一个数a_iai,如果这是一个质数,那么就把第a_iai小的质数添加到bb的末尾,否则,就把a_iai的最大的不等于a_iai的因子添加到bb的末尾。
最后把bb打乱顺序。
你需要找到任意一组合法的aa,使得aa可以生成bb。
思路:首先最重要的是发现对于一个质数而言,加入的新数是比原来质数更大的质数,对于一个合数而言,放入的新数是比原来数字更小的数字。
那么在给的b序列中,如果找到了一个最大的合数,那么是不是说这个合数只能是原来存在的而不是加的。因为质数只会让质数加入,而合数只会让更小的加入。
那么对于b序列中最小的质数而言,是不是意味着它不会被其他质数加入(可能被合数加入)
所以从大到小存下合数,每一个去删除/其最小质因子的数。
从小到大存下质数,每一个删去其对应的加入质因子primes[a[i]].
这些条件的判断在线性筛的板子里加一个flag[i]=1即可。
注意有个地方开map,不然空间不够。
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=2e5+100;
typedef long long LL;
LL v[5000005],primes[5000005];//v[i]存的是i的最小质因子,primes[m]里面存筛出来的质数
LL a[maxn*2],b[maxn*2],n;
bool flag[5000005];
map<LL,LL>s;//这里要用map
void getprimes(LL n)
{
// memset(v,0,sizeof(v));//最小质因子
LL m=0;//质数数量
for(LL i=2;i<=n;i++)
{
if(v[i]==0) {v[i]=i;primes[++m]=i;flag[i]=1;}//i是质数
//给当前的数i乘上一个质因子
for(LL j=1;j<=m;j++)
{
//i有比primes[j]更小的质因子,或者超出n的范围,停止循环
if(primes[j]>v[i]||primes[j]>n/i) break;
//primes[j]是合数i*primes[j]的最小质因子
v[i*primes[j]]=primes[j];
}
}
//for(LL i=1;i<=m;i++) cout<<primes[i]<<endl;
///cout<<"fuck"<<endl;
}
int main(void)
{
cin.tie(0);std::ios::sync_with_stdio(false);
getprimes(5000005);
cin>>n;
LL top1=0;LL top2=0;
for(LL i=1;i<=2*n;i++){
LL x;cin>>x;
if(flag[x]) a[++top1]=x;//质数
else b[++top2]=x; //合数
}
sort(b+1,b+top2+1);
sort(a+1,a+top1+1);
for(LL i=top2;i>=1;i--){
if(s[b[i]]){
s[b[i]]--;
continue;
}
cout<<b[i]<<" ";
s[b[i]/v[b[i]]]++;
}
for(LL i=1;i<=top1;i++){
if(s[a[i]]){
s[a[i]]--;
continue;
}
cout<<a[i]<<" ";
s[primes[a[i]]]++;
}
cout<<endl;
return 0;
}