bzoj 2301 [HAOI2011]Problem b(莫比乌斯反演+分块优化)

题意对于给出的n个询问,每次求有多少个数对(x,y),满足axbcyd,且gcd(x,y) = kgcd(x,y)函数为xy的最大公约数。

1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000

思路:莫比乌斯反演,ans=solve(b/k,d/k)-solve((a-1)/k,d/k)-solve(b/k,(c-1)/k)+solve((a-1)/k,(c-1)/k)

代码1:超时。

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;

const int MAXN=100000;
bool check[MAXN+10];
int prime[MAXN+10];
int mu[MAXN+10];
void Mobius(){
    memset(check,false,sizeof(check));
    mu[1]=1;
    int tot=0;
    for(int i=2;i<=MAXN;i++){
        if(!check[i]){
            prime[tot++]=i;
            mu[i]=-1;
        }
        for(int j=0;j<tot;j++){
            if(i*prime[j]>MAXN)break;
            check[i*prime[j]]=true;
            if(i%prime[j]==0){
                mu[i*prime[j]]=0;
                break;
            }
            else{
                mu[i*prime[j]]=-mu[i];
            }
        }
    }
}
//找[1,n],[1,m]内互质的数的对数
long long solve(int n,int m){
    long long ans=0;
    if(n>m)swap(n,m);
    for(int i=1;i<=n;i++)
        ans+=(long long)mu[i]*(n/i)*(m/i);
    return ans;
}

int main(){
    Mobius();
    int t;
    int a,b,c,d,k;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
        long long ans=solve(b/k,d/k)-solve((a-1)/k,d/k)-solve(b/k,(c-1)/k)+solve((a-1)/k,(c-1)/k);
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

代码2:用到分块优化。待研究。

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;

const int MAXN=100000;
bool check[MAXN+10];
int prime[MAXN+10];
int mu[MAXN+10];
void Mobius(){
    memset(check,false,sizeof(check));
    mu[1]=1;
    int tot=0;
    for(int i=2;i<=MAXN;i++){
        if(!check[i]){
            prime[tot++]=i;
            mu[i]=-1;
        }
        for(int j=0;j<tot;j++){
            if(i*prime[j]>MAXN)break;
            check[i*prime[j]]=true;
            if(i%prime[j]==0){
                mu[i*prime[j]]=0;
                break;
            }
            else{
                mu[i*prime[j]]=-mu[i];
            }
        }
    }
}
int sum[MAXN+10];
//找[1,n],[1,m]内互质的数的对数
long long solve(int n,int m){
    long long ans=0;
    if(n>m)swap(n,m);
    for(int i=1,la=0;i<=n;i=la+1){
        la=min(n/(n/i),m/(m/i));
        ans+=(long long)(sum[la]-sum[i-1])*(n/i)*(m/i);
    }
    return ans;
}

int main(){
    Mobius();
    sum[0]=0;
    for(int i=1;i<=MAXN;i++)
        sum[i]=sum[i-1]+mu[i];
    int t;
    int a,b,c,d,k;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
        long long ans=solve(b/k,d/k)-solve((a-1)/k,d/k)-solve(b/k,(c-1)/k)+solve((a-1)/k,(c-1)/k);
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

 

posted @ 2015-08-20 10:20  gongpixin  阅读(272)  评论(0编辑  收藏  举报