zoukankan      html  css  js  c++  java
  • BZOJ 3529: [Sdoi2014]数表

    二次联通门 : BZOJ 3529: [Sdoi2014]数表

    Latex的公式写起来略麻烦。。。

    设$LARGE F(x)=sum_{d|x} lfloor dfrac xd floor$

    $LARGE Answer = sum_{i=1}^nsum_{j=1}^{m}F(gcd(i,j))*[F(gcd(i,j)<=a]$

    当没有$a$的限制时

    $LARGE Answer = sum_{d=1}^{n}sum_{i=1}^{n}sum_{j=1}^{m}F(d)*[gcd(i,j)=d]$

                  $LARGE=sum_{d=1}^{n}F(d)sum_{i=1}^{n/d}sum_{j=1}^{m/d}[gcd(i,j)=1]$

    由莫比乌斯反演得(见BZOJ 1101: [POI2007]Zap):

    $LARGE Answer = sum_{d=1}^{n}F(d)sum_{i=1}^nmu(i)lfloor dfrac {n}{id} floor lfloor dfrac {m}{id} floor $

                $LARGE =sum_{d=1}^{n}lfloor dfrac nd floor lfloor dfrac md floorsum_{i|d}mu(dfrac ni)F(i)$

    然后对于 $LARGE sum_{d=1}^{n}lfloor dfrac nd floor lfloor dfrac md floor$可以$O(nsqrt n)$计算

    后一部分也可以预先预处理出来

    再把$a$的限制加上

    离线处理这个问题 

    将$F$和$a$都排个序,那么要计算的就是$F(i)<=a$的$i$

    那么就可以用树状数组维护$LARGE sum_{i|d}mu(dfrac ni)F(i)$的前缀和,每次插入小于当前$a$的$F[i]$,后每次询问前缀和即可

    /*
        BZOJ 3529: [Sdoi2014]数表
        
        树状数组+莫比乌斯反演
        
    */
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    
    #define rg register
    
    inline void read (int &n)
    {
        rg char c = getchar ();
        for (n = 0; !isdigit (c); c = getchar ());
        for (; isdigit (c); n = n * 10 + c - '0', c = getchar ());
    }
    #define Max 100000
    
    int t[Max + 9], p[Max + 9], mu[Max + 9]; bool is[Max + 9];
    inline int min (int a, int b) { return a < b ? a : b; }
    
    void Euler (int N)
    {
        rg int i, j, k; int C = 0; mu[1] = 1;
        for (i = 2; i <= N; ++ i)
        {
            if (!is[i]) p[++ C] = i, mu[i] = -1;
            for (j = 1; j <= C; ++ j)
            {
                if ((k = i * p[j]) > N) break;
                is[k] = true;
                if (i % p[j] == 0) { mu[k] = 0; break; }
                else mu[k] = -mu[i];
            }
        }
    }
    
    struct Q 
    { 
        int x, y; Q (int a = 0, int b = 0) : x (a), y (b) { } 
        bool operator < (const Q &rhs) const
        { return x == rhs.x ? y < rhs.y : x < rhs.x; }
    } f[Max + 9];
    
    void F ()
    {
        rg int i, j;
        for (i = 1; i <= Max; ++ i)
            for (j = i; j <= Max; j += i) f[j].x += i;
        for (i = 1; i <= Max; ++ i) f[i].y = i;
        std :: sort (f + 1, f + 1 + Max);
    }
    
    struct D 
    { 
        int n, m, a, id; 
        bool operator < (const D &rhs) const
        { return a < rhs.a; }
    } q[Max + 9];
    int Answer[Max + 9];
    
    inline int Query (int x)
    {
        int res = 0;
        for (rg int i = x; i; i -= i & (-i))
            res += t[i];
        return res;
    }
    void Change (int x, int k)
    { for (rg int i = x; i <= Max; i += i & (-i)) t[i] += k; }
    
    int Ask (int N, int M)
    {
        int res = 0, j; 
        if (N > M) std :: swap (N, M);
    
        for (rg int i = 1; i <= N; i = j + 1)
        {
            j = min (N / (N / i), M / (M / i));
            res += (N / i) * (M / i) * (Query (j) - Query (i - 1));
        }
        return res & 0x7fffffff;
    }
    
    int main (int argc, char *argv[])
    {
        int N, M; rg int i, j, k;
        Euler (Max); F ();
    
        int T; read (T);
        for (i = 1; i <= T; ++ i)
            read (q[i].n), read (q[i].m), read (q[i].a), q[i].id = i;
        std :: sort (q + 1, q + 1 + T);
    
        for (i = 1, j = 1; i <= T; ++ i)
        {
            for (; j <= Max && f[j].x <= q[i].a; ++ j)
                for (k = f[j].y; k <= Max; k += f[j].y)
                    Change (k, f[j].x * mu[k / f[j].y]);
            Answer[q[i].id] = Ask (q[i].n, q[i].m);    
        }
    
        for (i = 1; i <= T; ++ i)
            printf ("%d
    ", Answer[i]);
        return 0;
    }
  • 相关阅读:
    输入框联想
    SyntaxError: missing ; before statement 错误的解决
    Oracle数据库DECODE函数的使用.
    MySQL ----命令总结!
    个介!
    递归函数
    闭包函数与装饰器
    函数对象
    力扣题
    函数基础
  • 原文地址:https://www.cnblogs.com/ZlycerQan/p/8067463.html
Copyright © 2011-2022 走看看