bzoj3994 [SDOI2015]约数个数和

[SDOI2015]约数个数和

Time Limit: 20 Sec Memory Limit: 128 MB

Description

设d(x)为x的约数个数,给定N、M,求
\[\sum_{i=1}^N\ \sum_{j=1}^M d(ij)\]

Input

输入文件包含多组测试数据。

第一行,一个整数T,表示测试数据的组数。
接下来的T行,每行两个整数N、M。

Output

T行,每行一个整数,表示你所求的答案。

Sample Input

2

7 4

5 6

Sample Output

110

121

HINT

1<=N, M<=50000

1<=T<=50000





\[\sum_{i=1}^N\ \sum_{j=1}^M d(ij)\]
\[\sum_{i=1}^N\ \sum_{j=1}^M \sum_{x \mid i}\ \sum_{y \mid i} [(x,y)=1]\]
\[\sum_{i=1}^N\ \sum_{j=1}^M [(i,j)=1]\lfloor \frac{n}{i} \rfloor ]\lfloor \frac{m}{j} \rfloor\]
\[\sum_{i=1}^N\ \sum_{j=1}^M \lfloor \frac{n}{i} \rfloor ]\lfloor \frac{m}{j} \rfloor \sum_{d \mid i, d \mid j} \mu(d)\]
\[\sum_{d=1}^n \mu(d) \sum_{i=1}^{\lfloor \frac{n}{d} \rfloor} \lfloor \frac{n}{id} \rfloor \sum_{j=1}^{\lfloor \frac{m}{d} \rfloor} \lfloor \frac{m}{jd} \rfloor\]
然而就是后面的分块前面的强行套一波杜教筛。。。。




第一步那个
\[d(i,j)=\sum_{x \mid i} \sum_{y \mid i} [(x,y)=1]\]
我也很绝望了。。。。这个规律挺强的。。。。


#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e4 + 5;
int n, m, tot, prime[maxn];
long long f[maxn], mu[maxn];
bool not_prime[maxn];

inline void prepare()
{
    mu[1] = 1;
    for(int i = 2; i < maxn; ++i){
        if(!not_prime[i]){
            prime[++tot] = i; mu[i] = -1;
        }
        for(int j = 1; prime[j] * i < maxn; ++j){
            not_prime[i * prime[j]] = true;
            if(i % prime[j] == 0){mu[i * prime[j]] = 0; break;}
            mu[i * prime[j]] = -mu[i];
        }
    }
    for(int i = 2; i < maxn; ++i) mu[i] += mu[i - 1];
    
}

inline int F(int t)
{
    int last; int ret = 0;
    if(f[t]) return f[t];
    for(int i = 1; i <= t; i = last + 1){
        last = min(t, t / (t / i));
        ret += (last - i + 1) * (t / i);
    }
    return f[t] = ret;
}

inline void workk()
{
    long long ret = 0, last;
    for(long long d = 1; d <= n; d = last + 1){
        last = min(n / (n / d), (m / (m / d)));
        ret += (mu[last] - mu[d - 1]) * F(n / d) * F(m / d);
    }
    printf("%lld\n", ret);
}

int main()
{
    prepare();
    int T; scanf("%d", &T);
    while(T--){
        scanf("%d%d", &n, &m); if(n > m) swap(n, m);
        workk();
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/LLppdd/p/9214343.html