D. Recover it!(思维+模拟)

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;
}

猜你喜欢

转载自blog.csdn.net/zstuyyyyccccbbbb/article/details/108625946