[BZOJ 2301][HAOI2011] Problem b 莫比乌斯反演

来源:互联网 发布:电脑怎么解除网络限制 编辑:程序博客网 时间:2024/05/16 14:00

题目大意:

求n次询问a<=x<=b,c<=y<=d,使得Gcd(x,y)=k;

推导详见popoqqq大神orz:http://blog.csdn.net/popoqqq/article/details/41957687

1<=x<=n1<=y<=mGCD(x,y)=k1<=x<=nk1<=y<=mk[GCD(x,y)=1]1<=x<=nk1<=y<=mkd|gcd(x,y)μ(d)dμ(d)1<=x<=nk and d|nk1<=y<=mk and d|mk11<=d<=min(nk,mk))μ(d)ndmd

代码

#include <cstdio>#include <cstring>#include <iostream>using namespace std;typedef long long ll;namespace Mobius{    const int M=1000000;    int mu[M],check[M],cnt(0),prime[M],sum[M];      void Get_Mu() {        memset(sum,0,sizeof(sum));        memset(check,0,sizeof(check));        mu[1]=1;        for(int i=2;i<M;i++){            if(!check[i]){                mu[i]=-1;                prime[cnt++]=i;            }            for(int j=0;j<cnt;j++){                if(i*prime[j]>M) break;                check[i*prime[j]]=1;                if(i%prime[j]==0){                    mu[i*prime[j]]=0;                    break;                }else{                    mu[i*prime[j]]=-mu[i];                }            }        }        for(int i=1;i<=M;i++){            sum[i]=sum[i-1]+mu[i];        }    }}using namespace Mobius;int n,a,b,c,d,k;ll Solve(int n,int m,int k) {    n/=k;m/=k;    ll r=0;    int last(0);    for(int i=1;i<=min(n,m);i=last+1){        last=min(n/(n/i),m/(m/i));        r+=(ll)(sum[last]-sum[i-1])*(n/i)*(m/i);    }    return r;}int main() {    Get_Mu();    cin>>n;    for(int i=0;i<n;i++){        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));    }}
0 0
原创粉丝点击