CF1176D Recover it!
CF1176D Recover it!
题目描述
作者猜测了一个由 \(n\) 个整数构成的数组 \(a\),其中每个整数都不小于 \(2\) 且不大于 \(2 \cdot 10^5\)。你并不知道数组 \(a\),但你知道通过以下操作得到的数组 \(b\):
- 首先,让数组 \(b\) 等于数组 \(a\);
- 然后,对于每个 \(i\) 从 \(1\) 到 \(n\):
- 如果 \(a_i\) 是质数,则将一个整数 \(p_{a_i}\) 添加到数组 \(b\),其中 \(p\) 是质数的无限序列(\(2, 3, 5, \dots\));
- 否则(如果 \(a_i\) 不是质数),将 \(a_i\) 的最大真因子(不等于 \(a_i\) 的最大因子)添加到 \(b\);
- 最后,将得到的长度为 \(2n\) 的数组随机打乱顺序,并作为输入给你。
这里 \(p_{a_i}\) 表示第 \(a_i\) 个质数。第一个质数 \(p_1 = 2\),第二个质数是 \(p_2 = 3\),以此类推。
你的任务是还原出任意一个可以生成给定数组 \(b\) 的数组 \(a\)。保证一定存在解(即数组 \(b\) 是由某个合法的数组 \(a\) 生成的)。如果有多组解,你可以输出任意一组。
输入格式
第一行包含一个整数 \(n\)(\(1 \le n \le 2 \cdot 10^5\)),表示数组 \(a\) 的元素个数。
第二行包含 \(2n\) 个整数 \(b_1, b_2, \dots, b_{2n}\)(\(2 \le b_i \le 2750131\)),其中 \(b_i\) 是数组 \(b\) 的第 \(i\) 个元素。\(2750131\) 是第 \(199999\) 个质数。
输出格式
输出一行 \(n\) 个整数 \(a_1, a_2, \dots, a_n\)(\(2 \le a_i \le 2 \cdot 10^5\)),表示可以生成给定数组 \(b\) 的数组 \(a\),顺序任意。如果有多组解,你可以输出任意一组。
输入输出样例 #1
输入 #1
3
3 5 2 3 2 4
输出 #1
3 4 2
输入输出样例 #2
输入 #2
1
2750131 199999
输出 #2
199999
输入输出样例 #3
输入 #3
1
3 6
输出 #3
6
说明/提示
由 ChatGPT 4.1 翻译
算法分析
首先预处理出\(2750131\)以内的质数,用线性筛,因为后面要用到一个数组。然后,对输入的数排序,也可以用桶存,只要从大到小遍历就行。如果\(a_i\)是质数,那么它一定是被生成的那一个,因为如果是原数,那么之前一定会有一个比它要大的质数带掉它,所以它是被生成的数。如果\(a_i\)是合数,那么他一定是原数组其中一个,因为如果被生成,那么之前一定会有一个比它要小的合数带掉它,所以它是原数组之一。最后对于每一组,输出对应的数就行了。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2750131;
int n;
int k = 0;
int cnt[maxn+5];
int a[400005];
int pos[maxn+5];
int p[maxn+5];
int vis[maxn+5];
void xxs(){//线性筛
for(int i = 2; i<=maxn; i++){
if(vis[i]==0){
vis[i] = i;
p[++k] = i;
pos[i] = k;//对应是第几个质数
}
for(int j = 1; j<=k; j++){
if(p[j]>vis[i] || i*p[j]>maxn){
break;
}
vis[i*p[j]] = p[j];
}
}
}
int main(){
xxs();
cin>>n;
for(int i = 1; i<=2*n; i++){
int x;
cin>>x;
cnt[x]++;//桶
}
for(int i = maxn; i>=2; i--){
while(cnt[i]>0){//还有剩
if(pos[i]!=0){//是质数
int a = pos[i];//对应编号
cnt[i]--;
cnt[a]--;
cout<<a<<" ";
}else{
int t = i/vis[i];//最大因子
cnt[i]--;
cnt[t]--;
cout<<i<<" ";
}
}
}
return 0;
}
总结
这道题代码好些,思路好想,所以可以评到黄,感觉评不到绿。

浙公网安备 33010602011771号