• 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);
    }
    
  • 相关阅读:
    使用dtaidistance实现dtw算法(二)
    一元二次曲线拟合Excel用
    使用dtaidistance实现dtw算法
    一元二次曲线拟合
    爬取豆瓣电影top250
    pandasgui
    就业生态解析篇——数据预处理代码部分
    爬取51job招聘信息(一)
    负载均衡-LVS
    负载均衡
  • 原文地址:https://www.cnblogs.com/victorique/p/10414195.html
Copyright © 2020-2023  润新知