1. 程式人生 > >[HAOI2011]Problem b [Mobius]

[HAOI2011]Problem b [Mobius]

題意:

對於給出的n個詢問,每次求有多少個數對(x,y),滿足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函式為x和y的最大公約數。

100%的資料滿足:1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000

思路:

是之前做的求(1,n),(1,m)求gcd==k 這題的擴充套件版本,加個容斥

其中$$ f(a,b) $$(1,a),(1,b)求gcd==k

$$ ans=f(b,d)-f(a-1,d)-f(c-1,b)+f(a-1,c-1) $$

複雜度$$ O(q*\sqrt{n}) $$

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+5;
const int MOD=1e9+7;
int a,b,c,d,k;
template <class T>
bool sf(T &ret){ //Faster Input
    char c; int sgn; T bit=0.1;
    if(c=getchar(),c==EOF) return 0;
    while(c!='-'&&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');
    if(c==' '||c=='\n'){ ret*=sgn; return 1; }
    while(c=getchar(),c>='0'&&c<='9') ret+=(c-'0')*bit,bit/=10;
    ret*=sgn;
    return 1;
}
 
int mu[N], vis[N], prime[N];
ll summu[N];
int tot;//用來記錄prime的個數
void init(){
    mu[1] = 1;
    for(int i = 2; i < N; i ++){
        if(!vis[i]){
            prime[tot ++] = i;
            mu[i] = -1;
        }
        for(int j = 0; j < tot && i * prime[j] < N; j ++){
            vis[i * prime[j]] = 1;
            if(i % prime[j]) mu[i * prime[j]] = -mu[i];
            else{
                mu[i * prime[j]] = 0;
                break;
            }
        }
    }
    for(int i=1;i<N;i++)    summu[i]=mu[i]+summu[i-1];
}
ll f(int n,int m){
    ll ans=0;
    n/=k,m/=k;
    int mn=min(n,m);
    for(int d=1;d<=mn;++d){
//        ans+=mu[d]*(n/d)*(m/d);
        ll ed=min(n/(n/d),m/(m/d));
        ans+=(summu[ed]-summu[d-1])*(n/d)*(m/d);
        d=ed;
    }
    return ans;
}
int main(void){
    init();
    int q;
    sf(q);
    while(q--){
        sf(a);sf(b);sf(c);sf(d);sf(k);
        ll ans=f(b,d)-f(a-1,d)-f(c-1,b)+f(a-1,c-1);
        printf("%lld\n",ans);
    }
 
    return 0;
}