zoukankan      html  css  js  c++  java
  • BZOJ2154: Crash的数字表格

    BZOJ2154: Crash的数字表格


    题目描述

    传送门

    题目分析

    这题就是要求:

    [Ans=sum_{i=1}^nsum_{j=1}^m{lcm(i,j)} ]

    首先我们知道(lcm(a,b)=frac{ab}{gcd(a,b)}),然后就可把它代进去。

    [Ans=sum_{i=1}^nsum_{j=1}^mfrac{ij}{gcd(i,j)} ]

    然后根据套路,我们枚举(gcd)

    [Ans=sum_{d=1}^{min(n,m)}sum_{i=1}^nsum_{j=1}^mfrac{ij}{d}{[gcd(i,j)=d]} ]

    (d)提出去,可以得到:

    [Ans=sum_{d=1}^{min(n,m)}dsum_{i=1}^{lfloorfrac{n}{d} floor}sum_{j=1}^{lfloorfrac{m}{d} floor}ij[gcd(i,j)=1] ]

    根据莫比乌斯函数有趣的性质,可以化成:

    [Ans=sum_{d=1}^{min(n,m)}dsum_{i=1}^{lfloorfrac{n}{d} floor}sum_{i=1}^{lfloorfrac{m}{d} floor}ijsum_{xmid gcd(i,j)}mu(x) ]

    再把(x)放到外层枚举

    [Ans=sum_{d=1}^{min(n,m)}dsum_{x=1}^{min(lfloorfrac{n}{d} floor,lfloorfrac{m}{d} floor)}mu(x)sum_{i=1}^{lfloorfrac{n}{d} floor}sum_{j=1}^{lfloorfrac{m}{d} floor}ij[xmid gcd(i,j)] ]

    然后再把原式由枚举(i,j)变成枚举其(x)的倍数

    [Ans=sum_{d=1}^{min(n,m)}dsum_{x=1}^{min(lfloorfrac{n}{d} floor,lfloorfrac{m}{d} floor)}mu(x)x^2sum_{i=1}^{lfloorfrac{n}{dx} floor}sum_{j=1}^{lfloorfrac{m}{dx} floor}ij ]

    然后发现后面的(i,j)此时可以分开计算了。

    [Ans=sum_{d=1}^{min(n,m)}dsum_{x=1}^{min(lfloorfrac{n}{d} floor,lfloorfrac{m}{d} floor)}mu(x)x^2(sum_{i=1}^{lfloorfrac{n}{dx} floor}i)(sum_{j=1}^{lfloorfrac{m}{dx} floor}j) ]

    这个式子看上去是能过的,实际上某谷也是可以过的,但是BZOJ会T。

    这不禁让我们思考是否更加优秀的做法。

    可以发现其实刚才分开的部分是一个范围内的数对之和,我们设

    [f(n,m)=sum_{i=1}^{n}sum_{j=1}^{m}ij=frac{n imes (n+1)}{2}frac{m imes (m+1)}{2} ]

    这样后面的一坨就变成了

    [sum_{x=1}^{min(lfloorfrac{n}{d} floor,lfloorfrac{m}{d} floor)}mu(x)x^2f(lfloorfrac{n}{x} floor,lfloorfrac{m}{x} floor) ]

    明显这个式子是可以整数分块解的。

    我们设这类式子为(sum(n,m))

    则我们的原式就变成了

    [Ans=sum_{d=1}^{min(n,m)}d·sum(lfloorfrac{n}{d} floor,lfloorfrac{m}{d} floor) ]

    这个整数分块解的。
    那么使用整数分块套整数分块即可以在优秀的时间复杂度内完成本题。

    是代码呢

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN=1e7+7;
    #define ll long long
    const int mo=20101009;
    const ll inv=10050505;
    int n,m,prime[MAXN],mu[MAXN];
    ll sum[MAXN],ans;
    bool vis[MAXN];
    inline void get_mu(int N)
    {
        mu[1]=1;
        for(int i=2;i<=N;i++){
            if(!vis[i]){
                prime[++prime[0]]=i;
                mu[i]=-1;
            }
            for(int j=1;j<=prime[0];j++){
                if(1ll*i*prime[j]>N) break;
                vis[i*prime[j]]=1;
                if(i%prime[j]==0) break;
                mu[i*prime[j]]=-mu[i];
            }
        }
        for(int i=1;i<=N;i++) sum[i]=(sum[i-1]+1ll*i*i%mo*mu[i])%mo;
    }
    inline ll G(int x,int y)
    {
        return (1ll*x*(x+1)/2)%mo*(1ll*y*(y+1)/2%mo)%mo;
    }
    inline ll Sum(int x,int y)
    {
        ll summ=0;
        for(int l=1,r;l<=min(x,y);l=r+1){
            r=min(x/(x/l),y/(y/l));
            summ=(summ+1ll*(sum[r]-sum[l-1]+mo)*G(x/l,y/l)%mo)%mo;
        }
        return summ;
    }
    inline int read()
    {
        int x=0,c=1;
        char ch=' ';
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        while(ch=='-')c*=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*c;
    }
    int main()
    {
        n=read();m=read();
        get_mu(min(n,m)+1);
        int mx=min(n,m);
        for(int l=1,r;l<=mx;l=r+1){
            r=min(n/(n/l),m/(m/l));
            ans=(ans+1ll*(r-l+1)*(l+r)/2%mo*Sum(n/l,m/l)%mo)%mo;
        }
        printf("%lld
    ", (ans%mo+mo)%mo);
    }
    
  • 相关阅读:
    C#学习笔记——释放资源
    C#学习笔记——窗口停靠控件WeifenLuo.WinFormsUI.Docking使用
    C#学习笔记——查询串口被占用
    C#学习笔记——调试
    C#学习笔记——datagridview 控件 配置遇到的问题
    【转载】焊缝跟踪技术的发展与应用现状
    C#学习笔记——Convert.ToDouble与Double.Parse与Double.Parse
    C#学习笔记——Trim()、TrimStart()、TrimEnd()的用法
    C#学习笔记——DataGridView功能总结
    360自带--JS开发工具箱
  • 原文地址:https://www.cnblogs.com/victorique/p/10414195.html
Copyright © 2011-2022 走看看