【题解】【HAOI2011】Problem b

\(Luogu2522\)

题目大意:求下面式子的值:

\[\sum_{i=x}^n\sum_{j=y}^m[\gcd(i,j)=k]\]

这个东西直接求不好求,考虑差分,从\([1,n]\)的范围求,然后相减。

那么考虑:

\[\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=k]\]

同时除以\(k\)

\[\sum_{i=1}^{\frac{n}{k}}\sum_{j=1}^{\frac{m}{k}}[gcd(i,j)=1]\]

枚举\(d|gcd(i,j)\),套上反演套路,并且将\(d\)提到前面:

\[\sum_{i=1}^{\frac{n}{k}}\sum_{j=1}^{\frac{m}{k}}\sum_{d|gcd(i,j)}\mu(d)\]

\[=\sum_{d=1}^{n}\mu(i)\sum_{i=1}^{\frac{n}{kd}}\sum_{j=1}^{\frac{m}{kd}}\]

\[=\sum_{d=1}^{n}\mu(i)\frac{n}{kd}\frac{m}{kd}\]

这玩意到此结束,后面数论分块即可,\(O(\sqrt{n})\).

套一个差分即可。

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int MAXN=6e4+10;
int n,m;
int prime[MAXN],mu[MAXN];
int fg[MAXN],tot,sum[MAXN];
void screen(){
    mu[1]=1;
    for(int i=2;i<=MAXN;++i){
        if(!fg[i])prime[++tot]=i,mu[i]=-1;
        for(int j=1;j<=tot&&i*prime[j]<=MAXN;++j){
            fg[i*prime[j]]=1;
            if(i%prime[j]==0){
                mu[i*prime[j]]=0;
                break;
            }
            mu[i*prime[j]]=-mu[i];
        }
    }
    for(int i=1;i<=MAXN;++i)sum[i]=sum[i-1]+mu[i];
}
int solve(int x,int y,int k){
    int ans=0,M;
    M=min(x,y);
    for(int l=1,r;l<=M;l=r+1){
        r=min(x/(x/l),y/(y/l));
        ans+=(x/(l*k))*(y/(l*k))*(sum[r]-sum[l-1]);
    }
    return ans;
}
int main(){
    scanf("%d",&n);
    screen();
    for(;n;n--){
        int k,a,b,c,d;
        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
        printf("%d\n",solve(b,d,k)-solve(a-1,d,k)-solve(b,c-1,k)+solve(a-1,c-1,k));
    }
    return 0;
} 

猜你喜欢

转载自www.cnblogs.com/h-lka/p/12113230.html