【莫比乌斯】 HDU 1695 GCD
题意:这题求[1,n],[1,m]gcd为k的对数。而且没有顺序
思路:
设f(k)为gcd(x,y)=k的数对(x,y)的对数,我们要求的是f(1)
设F(k)为gcd(x,y)为k的倍数的数对(x,y)的对数,可以想到F(k)=floor(b/k)*floor(d/k),
由莫比乌斯反演得:
令lim=min(b/k,d/k)
f(1)=mu[1]*F(1) + mu[2]*F[2] + ... + mu[lim]*F(lim)
因为(n1,n2)和(n2,n1)算为同一种情况,所以最后结果还要减掉重复的情况
代码:
#include <cstdio> #include <algorithm> using namespace std; typedef long long ll; template <class T> inline bool rd(T &ret) { char c; int sgn; if(c = getchar() , c == EOF) return false; while(c != '-' && (c < '0' || c > '9')) c = getchar(); sgn = (c == '-') ? -1 : 1; ret = (c == '-') ? 0 : (c - '0'); while(c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0'); ret *= sgn; return true; } const int MAX_N = 1000007; int mu[MAX_N], cnt[MAX_N]; bool vis[MAX_N]; void Mobius(int n) { vis[1] = mu[1] = 1; for(int i = 1;i <= n; i++) mu[i] = 1; for(int i = 2;i <= n; i++) { if(!vis[i]) { for(int j = i;j <= n;j += i) { vis[j] = 1; mu[j] *= -1; if((j/i) % i == 0) mu[j] = 0; int t = j; while(t % i == 0) t /= i, cnt[j]++; } } } } int a, n, b, m, k; int main() { Mobius(1000001); int T, cas = 0; rd(T); while (T-- > 0) { rd(a), rd(n), rd(b), rd(m), rd(k); if (k == 0) { printf("Case %d: 0\n", ++cas); continue; } n /= k, m /= k; if (n > m) swap(n, m); ll ans = 0, ans1 = 0; for (int i = 1; i <= n; ++i) ans += (ll) mu[i] * (n / i) * (m / i); for (int i = 1; i <= n; ++i) ans1 += (ll) mu[i] * (n / i) * (n / i); ans = ans - ans1 / 2; printf("Case %d: %lld\n", ++cas, ans); } return 0; }