洛谷 P2522 [HAOI2011]Problem b

题目链接

先利用差分

思想,求\(f(b,d,k) - f(a - 1,d,k) - f(b,c-1,k)+f(a-1,c-1,k)\)

\[\begin{aligned} f(n,m,k) &=\sum_{i=1}^{n} \sum_{j=1}^{m} [\gcd(i,j) = k]\\ &= \sum_{i=1}^{\frac nk} \sum_{j=1}^{\frac mk} [\gcd(i,j) = 1]\\ \end{aligned}\\ \]

然后莫比乌斯反演

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

最后数论分块。

code

#include<bits/stdc++.h>
using namespace std;
int p[50050],prime[50050],cnt,mu[50050];
void init(int N){
    p[0] = p[1] = 1; mu[1] = 1;
    for(int i = 2; i <= N; ++ i){
        if(!p[i]) { prime[++ cnt] = i; mu[i] = -1; }
        for(int j = 1; 1ll * prime[j] * i <= N; ++ j){
            p[prime[j] * i] = 1;
            if(i % prime[j] == 0) break;
            mu[i * prime[j]] = -mu[i];
        }
    }
    for(int i = 1; i <= N; ++ i) mu[i] += mu[i - 1];
}
int f(int n, int m, int k){
    if(n > m) swap(n,m);
    n /= k; m /= k;
    if(n == 0 || m == 0) return 0;
    int ret = 0;
    for(int l = 1, r; l <= n; l = r + 1){
        r = min(min(n/(n/l), m/(m/l)), n);
        ret = ret + 1ll * (mu[r] - mu[l - 1]) * (n/l) * (m/l);
    }
    return ret;
}
int main(){
    init(50000);
    int T; scanf("%d",&T);
    while(T --){
        int a,b,c,d,k;
        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
        printf("%d\n",f(b,d,k) - f(a - 1,d,k) - f(b,c - 1,k) + f(a - 1,c - 1,k));
    }
	return 0;
}
posted @ 2020-08-13 20:19  zhuzihan  阅读(73)  评论(0编辑  收藏  举报