• P3312 [SDOI2014]数表


    题意描述:

    洛谷

    有一个 (n imes m) 的表格,第 (i) 行第 (j) 列的权值为 (sigma(gcd(i,j))) , 有 (Q) 组询问,每次问你一个 (n imes m) 的表格中,不大于 (a) 的数字之和。

    数据范围: (n,mleq 10^5, Qleq 2e4)

    前置芝士:

    1.线性筛约数个数

    (n = p_1^{k_1}p_2^{k_2}...p_n^{k_n}) , 那么 (sigma(n) = (1+p_1^1+p_1^2+..+p_1^{k_1})(1+p_2^1+p_2^2+...p_2^{k2}) ...)

    考虑维护一下两个数组:

    • (sd(i)) 表示 (i) 的约数个数和
    • (d(i)) 表示 (i) 的最小质因子的 ((1+p_1^1+p_1^2+..p_1^{k_1})) (实际上是个等比数列求和的形式)

    还是考虑分三种情况来考虑:

    • (i) 为质数,显然 (sd(i) = i+ 1) , (d(i) = i+1)

    • (i \% prime[j] eq 0) 的时候, (prime[j])(i imes prime[j]) 的最小质因子,那么

      (sd(i imes prime[j]) = sd(i) imes sd(prime[j]))

      (d(i imes prime[j]) = prime[j] + 1)

    • (i\% prime[j] = 0) 的时候,(i imes prime[j]) 的最小质因子次数为 (i) 的最小质因子次数加1。

      (sd(i imes prime[j]) = {sd(i)over d(i)} imes(d(i) imes prime[j]) + 1)

      (d(i imes prime[j]) = d(i) imes prime[j] + 1)

    然后在线性筛的时候分情况讨论即可。

    solution:

    我们要求的其实是:

    (displaystylesum_{i=1}^{n}sum_{j=1}^{m} sigma(gcd(i,j))[ sigma(gcd(i,j)) leq a])

    还是先枚举一下 (gcd) :

    (displaystylesum_{d=1}^{n} sigma(d)[sigma(d) leq a] sum_{i=1}^{n}sum_{j=1}^{m} [gcd(i,j) == d])

    先把 (gcd(i,j) == d) 反演掉:

    (displaystylesum_{d=1} ^{n}sigma(d) [sigma(d)leq a] sum_{i=1}^{nover d}sum_{j=1}^{mover d} [gcd(i,j) == 1])

    (displaystylesum_{d=1}^{n}sigma(d)[sigma(d) leq a] sum_{i=1}^{nover d}sum_{j=1}^{mover d} sum_{p|i,p|j}mu(p))

    (displaystylesum_{d=1}^{n}sigma(d) [sigma(d) leq a] sum_{p=1}^{nover d} mu(p) {nover {dp}} {mover dp})

    (dp)(Q) 可得:

    (displaystylesum_{Q=1}^{n} {nover Q}{mover Q} sum_{dmid Q} sigma(d)[sigma(d)leq a] mu({nover Q}))

    对于每组询问的话,我们很难直接做,考虑离线下来,按 (a) 从小到大排一下序。

    前面的那一坨可以用数论分块来解决,设 (displaystyle f(n) = sum_{dmid n} sigma(d) mu({nover d}))

    因为我们把询问按 (a) 从小到大排序,枚举询问时,(a) 的增大会使得一些 (sigma(d) leq a) ,这时候我们需要把他的贡献算上去。

    对于 (sigma(d)) 不难发现它会对他的倍数 (i imes d) 的贡献为 (sigma(d) mu(i))

    调和级数来枚举 (d) 的倍数,在拿个树状数组维护一下 $f(n) $ 前缀和即可。

    然后前面的整除分块,后面的就是 (f(r)-f(l-1)) ,在树状数组上查询即可。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define int long long
    const int p = (1<<31);
    const int N = 1e5+10;
    int cntq,maxn,tot,l = 1;
    int prime[N],mu[N],tr[N],omg[N],d[N],ans[N];
    bool check[N];
    struct QAQ
    {
        int w,id;
        QAQ(){}
        QAQ(int a,int b){id = a, w = b;}
    }e[N];
    struct node
    {
        int n,m,a,id;
    }q[N];
    inline int read()
    {
        int s = 0,w = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
        while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
        return s * w;
    }
    int lowbit(int x){return x & -x;}
    void chenge(int x,int val)
    {
        for(; x <= N-5; x += lowbit(x)) tr[x] += val;
    }
    int query(int x)
    {
        if(x == 0) return 0;
        int res = 0;
        for(; x; x -= lowbit(x)) res += tr[x];
        return res;
    }
    bool cmp(QAQ a,QAQ b)
    {
        return a.w < b.w;
    }
    bool comp(node a,node b)
    {
        return a.a < b.a;
    }
    void Add(int x)
    {
        for(int i = 1; i * e[l].id <= maxn; i++) chenge(i*e[l].id,omg[e[l].id] * mu[i]);
    }
    void YYCH()
    {
        mu[1] = 1; omg[1] = 1;
        for(int i = 2; i <= maxn; i++)
        {
            if(!check[i])
            {
                prime[++tot] = i;
                mu[i] = -1;
                omg[i] = i+1;
                d[i] = i+1;
            }
            for(int j = 1; j <= tot && i * prime[j] <= maxn; j++)
            {
                check[i * prime[j]] = 1;
                if(i % prime[j] == 0)
                {
                    mu[i * prime[j]] = 0;
                    d[i * prime[j]] = (d[i] * prime[j]) + 1;
                    omg[i * prime[j]] = (omg[i] / d[i]) * (d[i] * prime[j] + 1);
                    break;
                }
                else
                {
                    mu[i * prime[j]] = -mu[i];
                    d[i * prime[j]] = prime[j] + 1;
                    omg[i * prime[j]] = omg[i] * omg[prime[j]];
                }
            } 
        }
        for(int i = 1; i <= maxn; i++) e[i] = QAQ(i,omg[i]);
        sort(e+1,e+maxn+1,cmp);
    }
    int slove(int n,int m,int id)
    {
        int res = 0;
        while(l <= maxn && e[l].w <= q[id].a) Add(l), l++;
        for(int l = 1, r; l <= n; l = r+1)
        {
            r = min(n/(n/l),m/(m/l));
            res += (n/l) * (m/l) * (query(r)-query(l-1));
        }
        return res;
    }
    signed main()
    {
        cntq = read();
        for(int i = 1; i <= cntq; i++)
        {
            q[i].n = read();
            q[i].m = read();
            q[i].a = read();
            q[i].id = i;
            if(q[i].n > q[i].m) swap(q[i].n,q[i].m);
            maxn = max(maxn,q[i].n);
        }
        YYCH();
        sort(q+1,q+cntq+1,comp);
        for(int i = 1; i <= cntq; i++) ans[q[i].id] = slove(q[i].n,q[i].m,i);
        for(int i = 1; i <= cntq; i++) printf("%lld
    ",ans[i] % p);
        return 0;
    }
    
  • 相关阅读:
    读完此文让你了解各个queue的原理
    借汇编之力窥探String背后的数据结构奥秘
    汇编高手带你玩转字符串,快上车!
    语雀调研
    产品技能一:抽象能力
    我所认知的敏捷开发
    产品经理需要的技能,我有吗?
    孙正义采访:接下来的30年,一切将被重新定义
    5G小白鼠
    goto语句为啥不受待见
  • 原文地址:https://www.cnblogs.com/genshy/p/14387489.html
Copyright © 2020-2023  润新知