SP26017 GCDMAT

求:

i=i1i2j=j1j2gcd(i,j)(mod109+7)\sum_{i=i_1}^{i_2}\sum_{j=j_1}^{j_2}\gcd(i,j) \pmod{10^9+7}

TT 组数据。

其中,T50000,1i2,j2106T \leq 50000,1 \leq i2,j2\leq 10^6

首先设 S(n,m)=i=1nj=1mgcd(i,j)S(n,m)=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}\gcd(i,j)

ans=S(i2,j2)+S(i1,j1)S(i2,j1)S(i1,j2)ans=S(i_2,j_2)+S(i_1,j_1)-S(i_2,j_1)-S(i_1,j_2)

考虑化简 S(n,m)S(n,m),有:

S(n,m)=i=1nj=1mgcd(i,j)=d=1ndi=1nj=1m[gcd(i,j)=d]=d=1ndi=1ndj=1md[gcd(i,j)=1]=d=1ndi=1ndj=1mdpgcd(i,j)μ(p)=d=1ndi=1ndj=1mdp=1ndμ(p)[pi][pj]=d=1ndp=1ndμ(p)i=1ndj=1md[pi][pj]=d=1ndp=1ndμ(p)npdmpd=d=1ndp=1ndμ(p)npdmpd=T=1npTμ(p)TpnTmT设 T=dp=T=1nφ(T)nTmT\large \begin{aligned} S(n,m)&=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}\gcd(i,j)\\ &=\sum_{d=1}^{n}d\sum_{i=1}^{n}\sum_{j=1}^{m}[\gcd(i,j)=d]\\ &=\sum_{d=1}^{n}d\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}[\gcd(i,j)=1] \\ &=\sum_{d=1}^{n}d\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}\sum_{p|\gcd(i,j)}^{}\mu(p)\\ &=\sum_{d=1}^{n}d\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}\sum_{p=1}^{\lfloor\frac{n}{d}\rfloor}\mu(p)[p|i][p|j] \\ &=\sum_{d=1}^{n}d\sum_{p=1}^{\lfloor\frac{n}{d}\rfloor}\mu(p)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}[p|i][p|j] \\ &=\sum_{d=1}^{n}d\sum_{p=1}^{\lfloor\frac{n}{d}\rfloor}\mu(p)\lfloor\frac{n}{pd}\rfloor\lfloor\frac{m}{pd}\rfloor \\ &=\sum_{d=1}^{n}d\sum_{p=1}^{\lfloor\frac{n}{d}\rfloor}\mu(p)\lfloor\frac{n}{pd}\rfloor\lfloor\frac{m}{pd}\rfloor \\ &=\sum_{T=1}^{n}\sum_{p|T}\mu(p)\frac{T}{p}\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor & 设\ T=dp\\ &=\sum_{T=1}^{n}\varphi(T)\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor \\ \end{aligned}

这是 O(Tn)\mathcal{O}(T\sqrt{n}) 的算法,且常数巨大。

考虑优化,发现:

ans=i=1nφ(i)(i2ii1i)(j2ij1i)n=min(i2,j2)\large \begin{aligned} ans=\sum_{i=1}^{n}\varphi(i)(\lfloor\frac{i_2}{i}\rfloor-\lfloor\frac{i_1}{i}\rfloor)(\lfloor\frac{j_2}{i}\rfloor-\lfloor\frac{j_1}{i}\rfloor)&&n=\min(i_2,j_2) \end{aligned}

但是,还是过不了。

这里有一个好方法:预处理出 1N1\sim N 的倒数,然后把除法改成乘法,优化常数,可过。

但还可以优化。

考虑根号分治。

我们发现这实际上是一个预处理和查询的平衡,因为我们发现,llrr 越大,相同一段长度就越大,暴力的复杂度就相对越劣(意思就是用整除分块处理越快),那么我们可以考虑在 llrr 较小的时候暴力,否则预处理。

详见代码。

#pragma GCC optimize("Ofast")

#include <cstdio>

#include <cmath>

#define int long long

const int p = 1e9 + 7;

namespace Fread
{
    const int SIZE = 1 << 21;
    char buf[SIZE], *S, *T;
    inline char getchar()
    {
        if (S == T)
        {
            T = (S = buf) + fread(buf, 1, SIZE, stdin);
            if (S == T)
                return '\n';
        }
        return *S++;
    }
    inline int read()
    {
        int x = 0, f = 1;
        char c = getchar();
        while (c < '0' || c > '9')
        {
            if (c == '-')
                f = -1;
            c = getchar();
        }
        while (c >= '0' && c <= '9')
        {
            x = (x << 1) + (x << 3) + (c ^ 48);
            c = getchar();
        }
        return x * f;
    }
}

namespace Fwrite
{
    const int SIZE = 1 << 21;
    char buf[SIZE], *S = buf, *T = buf + SIZE;
    inline void flush()
    {
        fwrite(buf, 1, S - buf, stdout);
        S = buf;
    }
    inline void putchar(char c)
    {
        *S++ = c;
        if (S == T)
            flush();
    }
    struct NTR
    {
        ~NTR() { flush(); }
    } ztr;
    inline void write(int n, char c)
    {
        int tot = 0, a[101];
        while (n)
            a[++tot] = n % 10, n /= 10;
        if (!tot)
            putchar('0');
        else
            while (tot)
                putchar(a[tot--] + 48);
        putchar(c);
    }
}

int min(int n, int m)
{
    return n < m ? n : m;
}

int max(int n, int m)
{
    return n > m ? n : m;
}

int pri[10000001], sphi[10000001], phi[10000001], tot, N, mid;

double inv[10000001];

bool vis[1000001];

int opt;

int ge(int x, int y)
{
    if ((int)(x * inv[y]) != 0)
        return (int)(x * inv[(int)(x * inv[y])]);
    return opt;
}

void solve()
{
    sphi[1] = phi[1] = 1;
    for (int i = 2; i <= N; ++i)
    {
        if (!vis[i])
            pri[++tot] = i, sphi[i] = i - 1;
        for (int j = 1; j <= tot && pri[j] * i <= N; ++j)
        {
            vis[pri[j] * i] = 1;
            if (!(i % pri[j]))
            {
                sphi[pri[j] * i] = 1ll * sphi[i] * pri[j];
                break;
            }
            sphi[pri[j] * i] = 1ll * sphi[i] * (pri[j] - 1);
        }
        phi[i] = sphi[i];
    }
    for (int i = 1; i <= N; ++i)
        sphi[i] += sphi[i - 1], inv[i] = (1.00000000 / i) * (1 + 1e-15);
}

signed main()
{
    int t = Fread::read();
    N = max(Fread::read(), Fread::read());
    solve();
    while (t--)
    {
        int x1 = Fread::read() - 1, y1 = Fread::read() - 1, x2 = Fread::read(), y2 = Fread::read(), ans = 0;
        if (x2 > y2)
        {
            x1 ^= y1 ^= x1 ^= y1;
            x2 ^= y2 ^= x2 ^= y2;
        }
        opt = x2;
        mid = sqrt(y2 * 7);
        for (int i = 1; i <= mid; i++)
            ans += phi[i] * ((int)(x2 * inv[i]) - (int)(x1 * inv[i])) * ((int)(y2 * inv[i]) - (int)(y1 * inv[i]));
        ans %= p;
        for (int l = mid + 1, r; l <= x2; l = r + 1)
        {
            r = min(min(ge(x1, l), ge(y1, l)), min(ge(x2, l), ge(y2, l)));
            ans += 1ll * (sphi[r] - sphi[l - 1]) * ((int)(x2 * inv[l]) - (int)(x1 * inv[l])) * ((int)(y2 * inv[l]) - (int)(y1 * inv[l]));
            ans %= p;
        }
        Fwrite::write(ans, '\n');
    }
    return 0;
}
posted @ 2022-01-15 14:10  蒟蒻orz  阅读(1)  评论(0编辑  收藏  举报  来源