D. Not Adding 和 埃氏筛
题目大意:
一个数组有n个数。每次操作可以将数组中任意两个数字的gcd放入数组中(只有该gcd不在数组内时才能放入)。问最多能做几次操作。
思路和代码:
一个数字和另一个数字的gcd一定不会超过两数字的较小值。所以我们可以枚举1~MAX的所有数字,去判断他是否能尤若干个已经在数组内数字的gcd产生。当然,由若干个数字产生的最大公约数x一定和这些数字有倍数关系。所以可以用类似埃氏筛的做法,枚举x的倍数。
void solve(){
cin >> n ;
Clear() ;
rep(i , 1 , n){
cin >> a[i] ;
vis[a[i]] = 1 ;
m = max(m , a[i]) ;
}
rep(i , 1 , m){
if(vis[i]) continue ;//已经在集合中不用操作
ll prej = -1 ;//prej表示前若干个数的gcd
for(ll j = i + i ; j <= m ; j += i){
if(!vis[j]) continue ;//当枚举的i的倍数j在集合中
prej = prej == -1 ? j : __gcd(j , prej) ;
if(prej == i){//就有可能存在他和其他数字gcd等于i的情况
ans ++ ; break ;
}
}
}
cout << ans ;
}
拓展:
这题的枚举方式和埃氏筛很像,时间复杂度是mlogm
bool isprm[N] ;
ll prm[N] ;
ll Esieve(ll n){
ll res = 0 ;
isprm[0] = isprm[1] = 1 ;//1表示非质数
for(int i = 2 ; i <= n ; i ++ ){
if(!isprm[i]){
prm[++ res] = i ;
for(int j = i * 2 ; j <= n ; j += i)
isprm[j] = 1 ;
}
}
cout << res << ":\n" ;
rep(i , 1 , res) cout << prm[i] << " " ; cout << "\n" ;
}

浙公网安备 33010602011771号