码迷,mamicode.com
首页 > 其他好文 > 详细

【[国家集训队]Crash的数字表格 / JZPTAB】

时间:2019-01-01 21:08:44      阅读:1759      评论:0      收藏:0      [点我收藏+]

标签:组成   span   reg   iostream   spl   ons   有用   ret   cstring   

这道题我们要求的是

\[\sum_{i=1}^N\sum_{j=1}^Mlcm(i,j)\]

总所周知\(lcm\)的性质不如\(gcd\)优雅,但是唯一分解定理告诉我们\(gcd(i,j)\times lcm(i,j)=i\times j\)

所以很容易的可以转化成这个柿子

\[\sum_{i=1}^N\sum_{j=1}^M\frac{i\times j}{(i,j)}\]

现在开始套路了

先设两个函数

\[f(n)=\sum_{i=1}^N\sum_{j=1}^M[(i,j)==n]\times i\times j\]

\[F(n)=\sum_{i=1}^N\sum_{j=1}^M[n|(i,j)]\times i\times j\]

\[=\frac{n\times(\left \lfloor \frac{N}{n}\right \rfloor+1)\times \left \lfloor \frac{N}{n} \right \rfloor}{2}\times\frac{n\times(\left \lfloor \frac{M}{n}\right \rfloor+1)\times \left \lfloor \frac{M}{n} \right \rfloor}{2}\]

显然则有

\[F(n)=\sum_{n|d}f(d)\]

反演得

\[f(n)=\sum_{n|d}\mu(\frac{d}{n})F(d)\]

于是答案就是

\[Ans=\sum_{i=1}^N\frac{f(i)}{i}\]

\[=\sum_{i=1}^N\times\frac{1}{i}\sum_{i|d}\mu(\frac{d}{i})\frac{d\times(\left \lfloor \frac{N}{d}\right \rfloor+1)\times \left \lfloor \frac{N}{d} \right \rfloor}{2}\times\frac{d\times(\left \lfloor \frac{M}{d}\right \rfloor+1)\times \left \lfloor \frac{M}{d} \right \rfloor}{2}\]

后面的一大坨东西真是太烦人了,搞到前面来

\[Ans=\sum_{d=1}^N\frac{(\left \lfloor \frac{N}{d}\right \rfloor+1)\times \left \lfloor \frac{N}{d} \right \rfloor\times(\left \lfloor \frac{M}{d}\right \rfloor+1)\times \left \lfloor \frac{M}{d} \right \rfloor}{4}\sum_{i|d}\frac{\mu(\frac{d}{i})\times d^2}{i}\]

于是我们可以用\(\Theta(n \ln n)\)来求出\(\sum_{i|d}\frac{\mu(\frac{d}{i})\times d^2}{i}\)之后前缀和

于是有了一个\(70\)分的代码


#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define maxn 10000005
#define LL long long
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
const LL mod=20101009;
int n,m;
int f[maxn],p[maxn>>2];
LL pre[maxn];
int main()
{
    scanf("%d%d",&n,&m);
    if(n>m) std::swap(n,m);
    f[1]=pre[1]=1;
    for(re int i=2;i<=n;i++)
    {
        if(!f[i]) p[++p[0]]=i,pre[i]=(1-i+mod);
        for(re int j=1;j<=p[0]&&p[j]*i<=n;j++)
        {
            f[p[j]*i]=1;
            if(i%p[j]==0) 
            {
                pre[i*p[j]]=pre[i];
                break;
            }
            pre[p[j]*i]=pre[p[j]]*pre[i]%mod;
        }
    }
    for(re int i=1;i<=n;i++) pre[i]=(i*pre[i]%mod+pre[i-1])%mod;
    LL ans=0;
    for(re LL l=1,r;l<=n;l=r+1)
    {
        r=min(n/(n/l),m/(m/l));
        LL N=n/l,M=m/l;
        ans=(ans+((N+1)*N/2%mod)*((M+1)*M/2%mod)%mod*(pre[r]-pre[l-1]+mod)%mod)%mod;
    }
    printf("%lld\n",ans);
    return 0;
}

显然不行

我们设\(T=\frac{d}{i}\)

那么

\[\sum_{i|d}\frac{\mu(\frac{d}{i})\times d^2}{i}=d\times\sum_{T|d}\mu(T)\times T\]

定义\(h(x)=\sum_{T|x}\mu(T)\times T\)

会发现\(h\)是一个积性函数,可以考虑如何线筛

首先\(x\)是质数\(h(x)=1-x\)

互质的话可以直接乘起来

如果不互质的话需要好好考虑一下了

仔细思考一下这个\(h\)的含义,会发现有一些约数\(T\)是没有用的,就是那些\(\mu(T)=0\)的约数

而线筛的时候一旦\(i\%p[j]==0\),说明\(p[j]\)\(i\)中出现过,于是\(p[j]\)并不能组成一些新的有用约数,函数值和\(h(i)\)相比其实没有什么变化,所以就有

\[h(p[j]*i)=h(i)\]

于是现在的答案变成了

\[Ans=\sum_{d=1}^N\frac{(\left \lfloor \frac{N}{d}\right \rfloor+1)\times \left \lfloor \frac{N}{d} \right \rfloor\times(\left \lfloor \frac{M}{d}\right \rfloor+1)\times \left \lfloor \frac{M}{d} \right \rfloor}{4}\times d\times h(d)\]

于是直接求\(d\times h(d)\)的前缀和就好了

代码


#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define maxn 10000005
#define LL long long
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
const LL mod=20101009;
int n,m;
int f[maxn],p[maxn>>2];
LL pre[maxn];
int main()
{
    scanf("%d%d",&n,&m);
    if(n>m) std::swap(n,m);
    f[1]=pre[1]=1;
    for(re int i=2;i<=n;i++)
    {
        if(!f[i]) p[++p[0]]=i,pre[i]=(1-i+mod);
        for(re int j=1;j<=p[0]&&p[j]*i<=n;j++)
        {
            f[p[j]*i]=1;
            if(i%p[j]==0) 
            {
                pre[i*p[j]]=pre[i];
                break;
            }
            pre[p[j]*i]=pre[p[j]]*pre[i];
        }
    }
    for(re int i=1;i<=n;i++) pre[i]=(i*pre[i]%mod+pre[i-1])%mod;
    LL ans=0;
    for(re LL l=1,r;l<=n;l=r+1)
    {
        r=min(n/(n/l),m/(m/l));
        LL N=n/l,M=m/l;
        ans=(ans+((N+1)*N/2%mod)*((M+1)*M/2%mod)%mod*(pre[r]-pre[l-1]+mod)%mod)%mod;
    }
    printf("%lld\n",ans);
    return 0;
}

【[国家集训队]Crash的数字表格 / JZPTAB】

标签:组成   span   reg   iostream   spl   ons   有用   ret   cstring   

原文地址:https://www.cnblogs.com/asuldb/p/10205675.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有 京ICP备13008772号-2
迷上了代码!