Bzoj1101 Zap(莫比烏斯反演)
阿新 • • 發佈:2018-12-27
題面
題解
先化式子
$$ \sum_{x=1}^a\sum_{y=1}^b\mathbf f[gcd(x,y)==d] \\ = \sum_{x=1}^a\sum_{y=1}^b\sum_{d\mid x,d\mid y}\mathbf f[gcd(x,y)==1] \\ = \sum_{x=1}^{\lfloor \frac ad\rfloor}\sum_{y=1}^{\lfloor \frac bd\rfloor}\mathbf f[gcd(x,y)==1] $$
然後套路就類似於$Bzoj2818\ Gcd$了,只不過直接$\mathbf f$的逆直接變成了$\mu$。(我直接在那題基礎上改的)
#include <cstdio> #include <cstring> #include <algorithm> using std::min; using std::max; using std::swap; using std::sort; typedef long long ll; template<typename T> void read(T &x) { int flag = 1; x = 0; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') flag = -flag; ch = getchar(); } while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); x *= flag; } const int N = 5e4 + 10; int t, n, m, d, mu[N], g[N], prime[N], cnt; long long sum[N]; bool notprime[N]; void getmu(int k) { mu[1] = 1; for(int i = 2; i <= k; ++i) { if(!notprime[i]) prime[++cnt] = i, mu[i] = -1; for(int j = 1; j <= cnt && prime[j] * i <= k; ++j) { notprime[prime[j] * i] = true; if(!(i % prime[j])) break; mu[prime[j] * i] = -mu[i]; } } for(int i = 1; i <= k; ++i) sum[i] = sum[i - 1] + 1ll * mu[i]; } int main () { read(t); getmu(50000); while(t--) { read(n), read(m), read(d); ll ans = 0; n /= d, m /= d; if(n > m) swap(n, m); for(int l = 1, r; l <= n; l = r + 1) { r = min(n / (n / l), m / (m / l)); ans += (sum[r] - sum[l - 1]) * (m / l) * (n / l); } printf("%lld\n", ans); } return 0; }