• 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} floor ]lfloor frac{m}{j} floor$$ $$sum_{i=1}^N sum_{j=1}^M lfloor frac{n}{i} floor ]lfloor frac{m}{j} floor sum_{d mid i, d mid j} mu(d)$$ $$sum_{d=1}^n mu(d) sum_{i=1}^{lfloor frac{n}{d} floor} lfloor frac{n}{id} floor sum_{j=1}^{lfloor frac{m}{d} floor} lfloor frac{m}{jd} floor$$ 然而就是后面的分块前面的强行套一波杜教筛。。。。

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

    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 ", 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;
    }

    心如花木,向阳而生。
  • 相关阅读:
    泛型冒泡排序继承IComparable接口
    C#中枚举与位枚举的区别和使用
    C#中把二维数组转为一维数组
    一维数组的冒泡排序
    C#控制台的两个二维数组相加
    vs2019连接MySql的连接字符串
    Ajax方法请求WebService实现多级联动
    kafka-manager无法启动解决方法
    SQL优化————Insert
    读写锁
  • 原文地址:https://www.cnblogs.com/LLppdd/p/9214343.html
Copyright © 2020-2023  润新知