Codeforces 1627D Not Adding 题解 [ 绿 ] [ 最大公约数 ] [ 调和级数 ] [ 枚举 ]
Not Adding:一个 \(\gcd\) 的经典 trick。
对于求 \(\gcd\) 的题目,有一个经典 trick:枚举 \(\gcd\) 的值,然后枚举 \(\gcd\) 的每个倍数,计算每个倍数对 \(\gcd\) 的贡献。不难发现这个复杂度是调和级数的。
对于此题,题意可以转化为求最终能生成多少个数。因此我们枚举 \(\gcd\) 以及它的倍数,发现当所有倍数的 \(\gcd\) 等于它本身时,这个数可以被生成。于是直接调和级数复杂度枚举即可。时间复杂度 \(O(V\log V)\),注意本题复杂度不是 \(O(V\log^2 V)\),因为 \(\gcd\) 具有均摊性质,枚举每个 \(\gcd\) 的时候最多只会变化 \(\log V\) 次。
#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi = pair<int, int>;
const int N = 1000005;
int n, a[N], tot;
bitset<N> vis;
int gcd(int a, int b)
{
if(b == 0) return a;
return gcd(b, a % b);
}
int main()
{
//freopen("sample.in", "r", stdin);
//freopen("sample.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
for(int i = 1; i <= n; i++)
{
cin >> a[i];
vis[a[i]] = 1;
}
for(int i = 1; i < N; i++)
{
ll g = -1;
for(int j = i; j < N; j += i)
{
if(vis[j])
{
if(g == -1) g = j;
else g = gcd(g, j);
}
}
if(g == i) tot++;
}
cout << tot - n;
return 0;
}

浙公网安备 33010602011771号