zoukankan      html  css  js  c++  java
  • [bzoj46592694]Lcm_数论_莫比乌斯反演

    Lcm bzoj-4659 bzoj-2694

    题目大意:给出A,B,考虑所有满足l<=a<=A,l<=b<=B,且不存在n>1使得n^2同时整除a和b的有序数对(a,b),求其lcm(a,b)之和。答案模2^30。

    注释:$1le A,Ble 4cdot 10^6$,$1le cases le 2000$。

    想法:这题是一道挺好的题,它的好在于对于题目的转化。

    这题目描述,没个做,我们将它转化一下

    $ sumlimits_{i=1}^Asumlimits_{j=1}^Blcm(i,j)mu(gcd(i,j))^2$

    这时,就变成了一道反演的题目了。

    $=sumlimits_{i=1}^Asumlimits_{j=1}^Bsumlimits_{d|i,d|j}[gcd(i,j)=d]frac{ij}{d}mu(d)^2$

    $=sumlimits_{d=1}^Asumlimits_{i=1}^{lfloorfrac{A}{d} floor}sumlimits_{j=1}^{lfloorfrac{B}{d} floor}[gcd(i,j)==1]cdot dij cdot mu(d)^2$

    $=sumlimits_{d=1}^{A}mu(d)^2dsumlimits_{i=1}^{lfloorfrac{A}{d} floor}isumlimits_{j=1}^{lfloorfrac{B}{d} floor}jsumlimits_{e|i,e|j}mu(e)$

    $=sumlimits_{d=1}^Amu(d)^2dsumlimits_{e=1}^{lfloorfrac{A}{d} floor}mu(e)e^2sumlimits_{i=1}^{lfloorfrac{A}{de} floor}isumlimits_{j=1}^{lfloorfrac{B}{de} floor}j$

    $=sumlimits_{D=1}^ADsumlimits_{d|D}mu(d)^2mu(frac{D}{d})frac{D}{d}sum(lfloorfrac{A}{D} floor)sum(lfloorfrac{B}{D} floor)$

    此时,我们设函数

    $f(x)=sumlimits_{d|x}mu(d)^2mu(frac{x}{d})frac{x}{d}$

    $g(x)=mu(x)^2$

    $h(x)=xcdotmu(x)$

    因为g函数为积性函数,h函数为积性函数,所以函数$gcdot h$为积性函数,故f函数为积性函数,所以我们可以线性筛。

    最后,附上丑陋的代码... ...

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    typedef long long ll;
    const ll N=4000000;
    ll pri[N/10],np[N+10];
    ll f[N+10],s[N+10],sum[N+10],ans,msk;
    ll num,cases,n,m;
    inline char nc()
    {
        static char buf[100000],*p1,*p2;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int read()
    {
        int x=0;char c=nc();
        while(!isdigit(c))c=nc();
        while(isdigit(c))x=x*10+c-'0',c=nc();
        return x;
    }
    int main()
    {
        ll p,last;
        f[1]=s[1]=sum[1]=1;
        msk=1,msk<<=30,msk--;
        for(int i=2;i<=N;i++)
        {
            if(!np[i])  pri[++num]=i,f[i]=1-i;
            s[i]=s[i-1]+f[i]*i,sum[i]=sum[i-1]+i;
            for(int j=1;j<=num&&i*pri[j]<=N;j++)
            {
                p=pri[j],np[i*p]=1;
                if(i%p==0)
                {
                    if(i%(p*p)==0)  f[i*p]=0;
                    else    f[i*p]=f[i/p]*(-p);
                    break;
                }
                f[i*p]=f[i]*(1-p);
            }
        }
        cases=read();
        while(cases--)
        {
            n=read(),m=read(),ans=0;
            if(n>m)  swap(n,m);
            for(int i=1;i<=n;i=last+1)
            {
                last=min(n/(n/i),m/(m/i));
                ans+=(s[last]-s[i-1])*sum[n/i]*sum[m/i];
            }
            printf("%lld
    ",ans&msk);
        }
        return 0;
    }
    

    小结:反演好玩qwq...

  • 相关阅读:
    多线程中注意事项
    多线程实现第三种方式
    线程池《一》
    线程组
    线程间通信注意的问题
    互斥锁
    多个线程通信的问题
    二个线程间的通信
    死锁产生的原理
    线程安全问题
  • 原文地址:https://www.cnblogs.com/ShuraK/p/9320938.html
Copyright © 2011-2022 走看看