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。

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

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

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

$\ \ \sum\limits_{i=1}^A\sum\limits_{j=1}^Blcm(i,j)\mu(gcd(i,j))^2$

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

$=\sum\limits_{i=1}^A\sum\limits_{j=1}^B\sum\limits_{d|i,d|j}[gcd(i,j)=d]\frac{ij}{d}\mu(d)^2$

$=\sum\limits_{d=1}^A\sum\limits_{i=1}^{\lfloor\frac{A}{d}\rfloor}\sum\limits_{j=1}^{\lfloor\frac{B}{d}\rfloor}[gcd(i,j)==1]\cdot dij \cdot \mu(d)^2$

$=\sum\limits_{d=1}^{A}\mu(d)^2d\sum\limits_{i=1}^{\lfloor\frac{A}{d}\rfloor}i\sum\limits_{j=1}^{\lfloor\frac{B}{d}\rfloor}j\sum\limits_{e|i,e|j}\mu(e)$

$=\sum\limits_{d=1}^A\mu(d)^2d\sum\limits_{e=1}^{\lfloor\frac{A}{d}\rfloor}\mu(e)e^2\sum\limits_{i=1}^{\lfloor\frac{A}{de}\rfloor}i\sum\limits_{j=1}^{\lfloor\frac{B}{de}\rfloor}j$

$=\sum\limits_{D=1}^AD\sum\limits_{d|D}\mu(d)^2\mu(\frac{D}{d})\frac{D}{d}sum(\lfloor\frac{A}{D}\rfloor)sum(\lfloor\frac{B}{D}\rfloor)$

此时,我们设函数

$f(x)=\sum\limits_{d|x}\mu(d)^2\mu(\frac{x}{d})\frac{x}{d}$

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

$h(x)=x\cdot\mu(x)$

因为g函数为积性函数,h函数为积性函数,所以函数$g\cdot 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\n",ans&msk);
    }
    return 0;
}

小结:反演好玩qwq...