美文网首页
JZOJ1938 BZOJ2154 Crash的数字表格

JZOJ1938 BZOJ2154 Crash的数字表格

作者: ZJL_OIJR | 来源:发表于2018-08-15 21:21 被阅读0次

题目链接:BZOJ2154

思路

题目就是要你求
\sum_{i=1}^{n}\sum_{j=1}^{m}lcm(i,j)
考虑到
lcm(i,j)=\frac{ij}{gcd(i,j)}
式子变成:
\sum_{i=1}^{n}\sum_{j=1}^{m}\frac{ij}{gcd(i,j)}
gcd很烦,我们先枚举它:
\sum_{g=1}^{n}\frac{1}{g}\sum_{i=1}^{n}\sum_{j=1}^{m}ij[gcd(i,j)=g]
转换成gcd=1的形式:
\sum_{g=1}^{n}\frac{1}{g}\sum_{i=1}^{n/g}\sum_{j=1}^{m/g}ijg^2[gcd(i,j)=1]
就是:
\sum_{g=1}^{n}g\sum_{i=1}^{n/g}\sum_{j=1}^{m/g}ij[gcd(i,j)=1]
反演:
\sum_{g=1}^{n}g\sum_{i=1}^{n/g}\sum_{j=1}^{m/g}ij\sum_{d|gcd(i,j)}\mu(d)
\sum_{g=1}^{n}g\sum_{d=1}^{min(n/g,m/g)}\mu(d)\sum_{i=1}^{n/g/d}id\sum_{j=1}^{m/g/d}jd
\sum_{g=1}^{n}g\sum_{d=1}^{min(n/g,m/g)}\mu(d)d^2\sum_{i=1}^{n/g/d}i\sum_{j=1}^{m/g/d}j
然后发现,后面两个\sum其实是等差数列,可以O(1)求。前面的min(n/g,m/g)可以分块,后面的n/g/dm/g/d也可以分块,复杂度就是线性筛法复杂度+分块,也就是O(n)+O(\sqrt n * \sqrt n)=O(n)
在线筛的过程中顺便求一下\mu(d)d^2的前缀和,就可以随便搞了。

Code:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
inline int min(int a, int b) { return a < b ? a : b; }
 
typedef long long ll;
const int N = 1e7 + 7;
const ll P = 20101009;
 
int n, m, tot = 0, check[N], prime[N / 10], mu[N], sum[N];
ll ans = 0;
 
inline ll getsum(ll n) { return n * (n + 1) % P * 10050505LL % P; } //这个东西是2的逆元,别吓傻了
ll solve(int n, int m)
{
    ll ret = 0;
    for (int l = 1, r; l <= n; l = r + 1)
    {
        r = min(n / (n / l), m / (m / l));
        ret = (ret + (sum[r] - sum[l - 1] + P) % P * getsum(n / l) % P * getsum(m / l) % P) % P;
    }
    return ret;
}
 
int main()
{
    scanf("%d%d", &n, &m);
    if (n > m) n ^= m ^= n ^= m;
    mu[1] = sum[1] = 1;
    for (int i = 2; i <= n; i++)
    {
        if (!check[i]) prime[++tot] = i, mu[i] = -1;
        for (int j = 1; j <= tot; j++)
        {
            if (prime[j] * i > n) break;
            check[prime[j] * i] = 1;
            if (i % prime[j]) mu[prime[j] * i] = -mu[i];
            else { mu[prime[j] * i] = 0; break; }
        }
    }
    for (int i = 2; i <= n; i++) sum[i] = (sum[i - 1] + mu[i] * i % P * i % P) % P;
    for (int g = 1, r; g <= n; g = r + 1)
    {
        r = min(n / (n / g), m / (m / g));
        ans = (ans + (r - g + 1LL) * (r + g) % P * 10050505LL % P * solve(n / g, m / g) % P) % P;
    }
    printf("%lld\n", ans);
    return 0;
}

相关文章

网友评论

      本文标题:JZOJ1938 BZOJ2154 Crash的数字表格

      本文链接:https://www.haomeiwen.com/subject/qrlgbftx.html