题目
你有一个数组 a1,a2,…,an 由 n 个不同的整数组成。 您可以对其执行以下操作:
从数组 ai 和 aj (i≠j) 中选择两个元素,使得数组中不存在 gcd(ai,aj),并将 gcd(ai,aj) 添加到数组的末尾。 这里 gcd(x,y) 表示整数 x 和 y 的最大公约数 (GCD)。
注意每次操作后数组都会发生变化,后续的操作都是在新数组上进行的。
您可以对数组执行操作的最大次数是多少?
输入
第一行由一个整数 n (2≤n≤106) 组成。
第二行由 n 个整数 a1,a2,…,an (1≤ai≤106) 组成。 所有的 ai 都是不同的。
输出
输出包含一个整数的单行 - 可以对给定数组执行操作的最大次数。
题解思路
n为1e6 , 复杂度肯定是nlog及一下。
逆向思考
当一个数能被生成时,肯定时被几个这个数的倍数所生成。
利用调和级数,从大到小进行生成。
有可能新生成的数再生成新的数,但是新数字必然小于等于之前的数。
属实套路
AC代码
#include <bits/stdc++.h>
//#include <unordered_map>
//priority_queue
#define PII pair<int,int>
#define ll long long
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 1000100;
int a[N] ;
void solve()
{
int n ;
cin >> n ;
for (int i = 1 ; i <= n ; i++ )
{
int t1 ;
cin >> t1 ;
a[t1] = 1 ;
}
int ans = 0 ;
for (int i = 1e6 ; i >= 1 ; i-- )
{
if ( a[i] )
continue ;
int g = 0 ;
for ( int j = i ; j <= 1e6 ; j+= i )
{
if ( a[j] )
g = __gcd( g , j ) ;
}
if ( g == i )
ans++;
}
cout << ans << "\n" ;
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
solve() ;
return 0 ;
}