题目描述
给你一个包含n个正整数的序列 A = ( A 1 , A 2 , . . . , A n ) A=(A1,A2,...,An) A=(A1,A2,...,An),找到 [ 1 , m ] [1,m] [1,m]中每一个满足下列条件的 k k k:
g c d ( A i , k ) = 1 gcd(A_i,k)=1 gcd(Ai,k)=1, 1 ≤ i ≤ n 1≤i≤n 1≤i≤n
输入描述
第一行输入两个整数 n n n, m m m 第二行输入 n n n个整数代表序列 A A A
输出描述
第一行输出一个整数代表满足条件的k的数量 接下里每一行输出一个整数,代表一个满足条件的 k k k
样例输入
3 12
6 1 5
样例输出
3
1
7
11
数据范围
1 ≤ n , m ≤ 100000 1≤n,m≤100000 1≤n,m≤100000
1 ≤ a i ≤ 100000 1≤a_i≤100000 1≤ai≤100000
解题思路
本来这道题是想用欧拉筛做的(只考虑部分数情况下的“质数”),但是并不是质数就符合条件,因为互质要求是最大公约数为 1 1 1,而质数只是不能分解而已。
对于互质的数 a , b a,b a,b, g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1,也就是说互质的数不能有公因数。
我们将这个问题优化一下,互质的数不能有公共质因数(因为任何合数都可以分解为质数的乘积)。
那么现在我们的思路就是将所有输入分解为质因数,然后利用分解得到的质因数筛选符合条件的 k k k。
接下来是代码实现部分:
首先,我们需要知道如何将输入分解为质因数
int num;
for (int i = 0; i < n; i++) {
cin >> num;
while (num != 1) {
fliter[maxPrime[num]] = true;
num /= maxPrime[num];
}
}
其实,就是将 n u m num num不断除以其最大质因数。
那么问题出现了,如何求任意数的最大质因数?这里采用埃氏筛的算法(简而言之就是用质数的倍数筛去非质数)的变形:
memset(isPrime + 1, true, sizeof(bool) * max_n);//初始化,默认所有数均为质数
maxPrime[1] = 1;//对1进行特殊处理
isPrime[1] = false;
for (int i = 2; i <= max_n; i++) {
if (!isPrime[i]) continue;//非质数
maxPrime[i] = i;
for (int j = 2 * i; j <= max_n; j += i) {
isPrime[j] = false;
maxPrime[j] = i;
}
}
筛子做好了,接下来就是筛选 1 1 1~ M M M的所有数了:
vector<int>v;
v.push_back(1);//对1进行特殊处理
for (int i = 2; i <= m; i++) {
bool flag = true;
int temp = i;
while (temp != 1) {
if (fliter[maxPrime[temp]]) {
flag = false;
break;
}
temp /= maxPrime[temp];
}
if (flag) v.push_back(i);
}
在题目之初提到的问题就是筛选一个 k k k,既需要考虑 k k k能否分解为小于 k k k的数,又要考虑 k k k之后的数是否为 k k k的倍数。
但是现在我们将序列 A A A中的元素分解了,就没有这个问题了,只需要考虑 k k k能否分解即可。
最后,AC代码如下:
#include <iostream>
#include <vector>
#include <string.h>
using namespace std;
const int max_n = 100000;
bool isPrime[max_n + 1], fliter[max_n + 1]; //质数数组, 筛子
int maxPrime[max_n + 1]; //最大质因数
int main() {
//prepare
memset(isPrime + 1, true, sizeof(bool) * max_n);//初始化,默认所有数均为质数
maxPrime[1] = 1;//对1进行特殊处理
isPrime[1] = false;
for (int i = 2; i <= max_n; i++) {
if (!isPrime[i]) continue;//非质数
maxPrime[i] = i;
for (int j = 2 * i; j <= max_n; j += i) {
isPrime[j] = false;
maxPrime[j] = i;
}
}
//input
int n, m, num;
cin >> n >> m;
for (int i = 0; i < n; i++) {
cin >> num;
while (num != 1) {
fliter[maxPrime[num]] = true;
num /= maxPrime[num];
}
}
//fliter
vector<int>v;
v.push_back(1);//对1进行特殊处理
for (int i = 2; i <= m; i++) {
bool flag = true;
int temp = i;
while (temp != 1) {
if (fliter[maxPrime[temp]]) {
flag = false;
break;
}
temp /= maxPrime[temp];
}
if (flag) v.push_back(i);
}
//output
cout << v.size() << endl;
for (auto iter : v) {
cout << iter << endl;
}
return 0;
}