BZOJ2301 HAOI2011 problem b 莫比乌斯反演+容斥原理

题意:N组询问,每次给出a b c d k,求满足a≤x≤b,c≤y≤d且gcd(x,y)=k的数对(x,y)的数量。

题解:

设fA,B,k表示1≤x≤A,1≤y≤B内合法数对的数量,那么答案就是fb,d-fa,d-fb,c+fa,c。设FA,B,i=i|gcd(x,y)(i=tk,1≤x≤A,1≤y≤B)的数对数量,显然\[{F_{A,B,i}} = \left\lfloor {\frac{A}{i}} \right\rfloor \left\lfloor {\frac{B}{i}} \right\rfloor  = \sum\limits_{k|i} {{f_{A,B,k}}} \]

反演之后得到\[{f_{A,B,k}} = \sum\limits_{k|i} {\mu (\frac{i}{k}){F_{A,B,i}}} \]

然后进行函数分块即可

#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long

const int MAXN=60000+2;
int N,a,b,c,d,K,mu[MAXN],prime[MAXN];
bool flag[MAXN];

void Moebius(int N,int *mu){
    mu[1]=1;
    for(int i=2,j=0;i<=N;i++){
        if(!flag[i]) prime[++j]=i,mu[i]=-1;
        for(int k=1;k<=j && i*prime[k]<=N;k++){
            flag[i*prime[k]]=1;
            if(i%prime[k]==0){
                mu[i*prime[k]]=0;
                break;
            }
            mu[i*prime[k]]=-mu[i];
        }
    }
    for(int i=2;i<=N;i++) mu[i]+=mu[i-1];
}

ll Solve(int N,int M,int K){
    ll ret=0;
    N/=K,M/=K;
    for(int i=1,j;i<=M && i<=N;i=j+1){
        j=min(N/(N/i),M/(M/i));
        ret+=(ll)(mu[j]-mu[i-1])*(N/i)*(M/i);
    }
    return ret;
}

int main(){
    Moebius(MAXN,mu);

    cin >> N;
    while(N--){
        scanf("%d %d %d %d %d",&a,&b,&c,&d,&K);
        printf("%lld\n",Solve(b,d,K)-Solve(a-1,d,K)-Solve(b,c-1,K)+Solve(a-1,c-1,K));
    }

    return 0;
}
View Code

 

posted @ 2017-02-26 22:22  WDZRMPCBIT  阅读(...)  评论(...编辑  收藏