• [bzoj2154]Crash的数字表格


    来自FallDream的博客,未经允许,请勿转载,谢谢。


    题意:求$$sum_{i=1}^{n}sum_{j=1}^{m}lcm(i,j)   \    n,mleqslant 10^{7}$$

    之前有做过一道类似的题目,nm相同,但是最大有$10^{10}$,可以用欧拉函数+杜教筛解决。

    但是这道题n与m不同,欧拉函数就没办法排上用场了,还是换换思路吧。由于求的是lcm,所以考虑枚举gcd是p。假装n<m,得到

    $$Ans=sum_{p=1}^{n}sum_{i=1}^{lfloorfrac{n}{p} floor}sum_{j=1}^{lfloorfrac{m}{p} floor}p*i*jsum_{d|i,d|j}mu(d)$$

    把d提出来,发现计算的次数是一个等差数列两两相乘,令$G(n)=sum_{i=1}^{n}i$,那么

    $$Ans=sum_{p=1}^{n}p*sum_{d=1}^{lfloorfrac{n}{p} floor}mu(d)*d^{2}*S(lfloorfrac{n}{pd} floor)*S(lfloorfrac{m}{pd} floor)$$

    然后老套路,令T=pd,得到

    $$Ans=sum_{T=1}^{n}T*S(lfloorfrac{n}{T} floor)*S(lfloorfrac{m}{T} floor)*sum_{d|T}mu(d)*d$$

    所以我们只需要预处理出$F[T]=sum_{d|T}mu(d)*d$就行了。

    嗯我推到这里感觉很正确就交了一个类似欧拉筛的东西上去,妥妥T掉了....

    但其实并不需要,$F[T]$其实是积性函数,这个可以自己脑补,然后可以线筛出来。

    假设p是质数,那么p|i的时候,$F[i*p]=F[i]$,因为新的项的μ都是0.

    如果不能整除,那么$F[i*p]=F[i]*F[p]$

    这样就可以过啦。最后的计算可以每次$sqrt{n}$做,当然直接暴力也是可以的。

    #include<iostream>
    #include<cstdio>
    #include<ctime>
    #define MN 10000000
    #define mod 20101009
    #define ll long long
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    int n,m,s[MN],num=0,ans=0,f[MN+5];
    bool b[MN+5];
    
    inline int calc(int x,int y){return 1LL*(1+(x/y))*(x/y)%mod*10050505%mod;}
    
    int main()
    {
        f[1]=1;
        for(register int i=2;i<=MN;++i)
        {
            if(!b[i]) s[++num]=i,f[i]=mod+1-i;
            for(int j=1;s[j]*i<=MN;++j)
            {
                b[s[j]*i]=1;
                if(i%s[j]==0) {f[s[j]*i]=f[i];break;}
                f[s[j]*i]=1LL*f[i]*f[s[j]]%mod;
            }
        }
        for(register int i=2;i<=MN;++i) f[i]=(1LL*f[i]*i+f[i-1])%mod;
        n=read();m=read();if(n>m) swap(n,m);
        for(register int i=1,last;i<=n;i=last+1)
        {
            last=min(m/(m/i),n/(n/i));
            ans=(ans+1LL*(f[last]-f[i-1]+mod)*calc(n,i)%mod*calc(m,i)%mod)%mod;
        }
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    字符串转换整数
    list、tuple、dict加*星号
    字符串
    整数反转
    字符串分割函数
    核密度图(直方图的拟合曲线)
    不同缺失值的删除方法
    Z字形变换
    最长回文字串
    寻找两个有序数组的中位数
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj2154.html
Copyright © 2020-2023  润新知