【莫比乌斯】 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;
}
View Code

 

posted @ 2015-08-17 21:39  mithrilhan  阅读(144)  评论(0编辑  收藏  举报