【莫比乌斯反演】[BZOJ2301]Problem b

思路,这个令F(i)=nimi 显然这个就是n和m以内的含有公因数i的对数,然后发现对于 a, b来说实际上就是求a/k 和 b/k范围以内的互质数的对数,然后发现发现答案=公因数为1的个数(不是最大)-公因数为一个质数的对数+公因数为两个质数的对数,然后就和BZOJ2440很像了,然后改一下就行了,最后根据容斥原理 答案=solve(b/k, d/k) - solve((a-1)/k, d/k) - solve((c-1)/k, b/k) + solve((a-1)/k, (c-1)/k)
以下是我的代码

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 50000;
int mu[MAXN+10], prime[MAXN+10], pcnt;
bool notprime[MAXN+10];
long long solve(int n, int m){
    long long ret = 0;
    if(n > m) swap(n, m);
    for(int i=1, nex;i<=n;i=nex+1){
        nex = min(n/(n/i), m/(m/i));
        ret += 1LL * (mu[nex] - mu[i-1]) * (n/i) * (m/i);
    }
    return ret;
}
void Init(int t){
    mu[1] = 1;
    int tmp;
    for(int i=2;i<=t;i++){
        if(!notprime[i]){
            prime[++pcnt] = i;
            mu[i] = -1;
        }
        for(int j=1;j<=pcnt&&(tmp=prime[j]*i)<=t;j++){
            notprime[tmp] = true;
            if(i % prime[j] == 0){
                mu[tmp] = 0;
                break;
            }
            mu[tmp] = -mu[i];
        }
    }
    for(int i=2;i<=t;i++)
        mu[i] += mu[i-1];
}
int main(){
    int n;
    Init(50000);
    scanf("%d", &n);
    while(n--){
        int k, a, b, c, d;
        scanf("%d %d %d %d %d", &a, &b, &c, &d, &k);
        printf("%lld\n", solve(b/k, d/k) - solve((a-1)/k, d/k) - solve((c-1)/k, b/k) + solve((a-1)/k, (c-1)/k));
    }

    return 0;
}

posted on 2015-06-02 19:03  JeremyGuo  阅读(104)  评论(0编辑  收藏  举报

导航