• BZOJ 3994: [SDOI2015]约数个数和 [莫比乌斯反演 转化]


    2015

    题意:(d(i))为i的约数个数,求(sumlimits_{i=1}^n sumlimits_{j=1}^m d(ij))


    (ij)都爆int了....
    一开始想容斥一下用(d(i))(d(j))(d(ij)),发现不行...
    然后翻题解看到了一步好神的转化:

    [d(nm) = sum_{imid n} sum_{jmid m} [gcd(i,j)=1] ]

    晚上再补吧还是没拿草稿纸...


    补:
    (Proof.)

    • 首先注意约数个数 相同的算一个
      约数个数公式(prod (a_i+1))
      考虑一个质因子,(p^x,p^y ightarrow p^x p^y)
      (x+y+1)对应了(gcd(p^x, 1)...gcd(1, 1)...gcd(1,p^y))
      质因子相互独立,乘起来

    然后愉♂悦的套路推♂倒

    [egin{align*} sum_{i=1}^n sum_{j=1}^m d(ij) &= sum_{i=1}^n sum_{j=1}^m sum_{xmid i} sum_{ymid j} [gcd(x,y)=1]\ 先枚举约数,交换i,j x,y\ &=sum_{i=1}^n sum_{j=1}^m sum_{dmid i,dmid j}mu(d) frac{n}{i} frac{m}{i}\ &=sum_{d=1}^n mu(d)sum_{i=1}^frac{n}{i} sum_{j=1}^frac{m}{i} frac{n}{id}frac{m}{jd}\ &=sum_{d=1}^n mu(d) f(frac{n}{id})f(frac{m}{jd})\ end{align*} ]

    问题就是(f(n)=sum_{i=1}^nfrac{n}{i})怎么求了
    可以n根n预处理...
    更巧妙的做法是,发现(f)就是(d)的前缀和,因为(frac{n}{i})表示的就是(1..n)有几个i的倍数

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int N=5e4+5;
    typedef long long ll;
    #define pii pair<int, int>
    #define MP make_pair
    #define fir first
    #define sec second
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
     
    int n, m;
    int notp[N], p[N], mu[N]; ll f[N]; pii lp[N];
    void sieve(int n) {
        mu[1] = 1; f[1] = 1;
        for(int i=2; i<=n; i++) {
            if(!notp[i]) p[++p[0]] = i, mu[i] = -1, f[i] = 2, lp[i] = MP(i, 1);
            for(int j=1; j<=p[0] && i*p[j]<=n; j++) {
                int t = i*p[j];
                notp[t] = 1;
                if(i%p[j] == 0) {
                    mu[t] = 0;
                    lp[t] = MP(p[j], lp[i].sec + 1);
                    f[t] = f[i] / (lp[i].sec + 1) * (lp[t].sec + 1);
                    break;
                }
                mu[t] = -mu[i];
                lp[t] = MP(p[j], 1);
                f[t] = f[i] * (lp[t].sec + 1);
            }
        }
        for(int i=1; i<=n; i++) mu[i] += mu[i-1], f[i] += f[i-1];
    }
    ll cal(int n, int m) {
        ll ans=0; int r;
        for(int i=1; i<=n; i=r+1) {
            r = min(n/(n/i), m/(m/i)); 
            ans += (mu[r] - mu[i-1]) * f[n/i] * f[m/i];
        }
        return ans;
    }
    int main() {
        //freopen("in","r",stdin);
        sieve(N-1);
        int T=read();
        while(T--){
            n=read(); m=read();
            if(n>m) swap(n, m);
            printf("%lld
    ",cal(n, m));
        }
    }
    
  • 相关阅读:
    [转]linux top 命令
    [转]Linux下实用的查看内存和多核CPU状态命令
    Totem ring protocal
    qemu qemusystemx86_64 qemukvm kvm 四个命令
    jsp>过滤器 小强斋
    jsp>Tomcat 6.0数据源配置记录 小强斋
    jsp>过滤器 小强斋
    jsp>监听器 小强斋
    jsp>Tomcat 6.0数据源配置记录 小强斋
    jsp>jsp执行过程 小强斋
  • 原文地址:https://www.cnblogs.com/candy99/p/6611672.html
Copyright © 2020-2023  润新知