题意简述
求
∑i=1n∑j=1mlcm(i,j)\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}lcm(i,j)i=1∑nj=1∑mlcm(i,j)
(其中n,m<=1e7n,m<=1e7n,m<=1e7)
数据
输入
4 5
输出
122
思路
一看就知道是反演。。。
来推式子吧!
令g=gcd(i,j)g=gcd(i,j)g=gcd(i,j),n<=mn<=mn<=m
原式
=∑i=1n∑j=1mijg这个就是化了一下lcm(i,j)=∑d=1n∑i=1n∑j=1m[g==d]ijd这个就是提前枚举gcd(i,j),然后后面找哪些会算到=∑d=1n∑id=dn∑jd=dm[g==1]id∗jdd=∑d=1n∑i=1n/d∑j=1m/d[g==1]ijdi,j换成枚举d的几倍,注意换成枚举倍数后i变成id,j变成jd,所以多乘一个d2,原来是ijd,变成ijd=∑d=1n∑i=1n/d∑j=1m/d∑q∣gμ(q)ijd把[g==1]换成了ϵ(g),然后用了一下反演式=∑d=1n∑q=1n/d∑i=1n/d∑j=1m/d[q∣g]μ(q)ijd提前枚举q,看后面有哪些算到的=∑d=1n∑q=1n/d∑iq=1n/d∑jq=1m/d[1∣g]μ(q)iq∗jq∗di,j有变成了枚举q的倍数,注意i变成iq,j变成jq,所以多乘一个q2=∑d=1n∑q=1n/d∑i=1n/dq∑j=1m/dqμ(q)ijq2d稍作整理,去掉了没什么用的[1∣g](因为不管g多少这个都成立)=∑d=1nd∑q=1n/dq2μ(q)∑i=1n/dqi∑j=1m/dqj进一步的整理,把无关的提到最前
=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}\frac{ij}{g}\\
这个就是化了一下lcm(i,j)\\
=\sum\limits_{d=1}^{n}\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}[g==d]\frac{ij}{d}\\
这个就是提前枚举gcd(i,j),然后后面找哪些会算到\\
=\sum\limits_{d=1}^{n}\sum\limits_{id=d}^{n}\sum\limits_{jd=d}^{m}[g==1]\frac{id*jd}{d}\\
=\sum\limits_{d=1}^{n}\sum\limits_{i=1}^{n/d}\sum\limits_{j=1}^{m/d}[g==1]ijd\\
i,j换成枚举d的几倍,注意换成枚举倍数后i变成id,j变成jd,所以多乘一个d^2,原来是\frac{ij}{d},变成ijd\\
=\sum\limits_{d=1}^{n}\sum\limits_{i=1}^{n/d}\sum\limits_{j=1}^{m/d}\sum\limits_{q|g}\mu(q)ijd\\
把[g==1]换成了\epsilon(g),然后用了一下反演式\\
=\sum\limits_{d=1}^{n}\sum\limits_{q=1}^{n/d}\sum\limits_{i=1}^{n/d}\sum\limits_{j=1}^{m/d}[q|g]\mu(q)ijd\\
提前枚举q,看后面有哪些算到的\\
=\sum\limits_{d=1}^{n}\sum\limits_{q=1}^{n/d}\sum\limits_{iq=1}^{n/d}\sum\limits_{jq=1}^{m/d}[1|g]\mu(q)iq*jq*d\\
i,j有变成了枚举q的倍数,注意i变成iq,j变成jq,所以多乘一个q^2\\
=\sum\limits_{d=1}^{n}\sum\limits_{q=1}^{n/d}\sum\limits_{i=1}^{n/dq}\sum\limits_{j=1}^{m/dq}\mu(q)ijq^2d\\
稍作整理,去掉了没什么用的[1|g](因为不管g多少这个都成立)\\
=\sum\limits_{d=1}^{n}d\sum\limits_{q=1}^{n/d}q^2\mu(q)\sum\limits_{i=1}^{n/dq}i\sum\limits_{j=1}^{m/dq}j\\
进一步的整理,把无关的提到最前\\
=i=1∑nj=1∑mgij这个就是化了一下lcm(i,j)=d=1∑ni=1∑nj=1∑m[g==d]dij这个就是提前枚举gcd(i,j),然后后面找哪些会算到=d=1∑nid=d∑njd=d∑m[g==1]did∗jd=d=1∑ni=1∑n/dj=1∑m/d[g==1]ijdi,j换成枚举d的几倍,注意换成枚举倍数后i变成id,j变成jd,所以多乘一个d2,原来是dij,变成ijd=d=1∑ni=1∑n/dj=1∑m/dq∣g∑μ(q)ijd把[g==1]换成了ϵ(g),然后用了一下反演式=d=1∑nq=1∑n/di=1∑n/dj=1∑m/d[q∣g]μ(q)ijd提前枚举q,看后面有哪些算到的=d=1∑nq=1∑n/diq=1∑n/djq=1∑m/d[1∣g]μ(q)iq∗jq∗di,j有变成了枚举q的倍数,注意i变成iq,j变成jq,所以多乘一个q2=d=1∑nq=1∑n/di=1∑n/dqj=1∑m/dqμ(q)ijq2d稍作整理,去掉了没什么用的[1∣g](因为不管g多少这个都成立)=d=1∑ndq=1∑n/dq2μ(q)i=1∑n/dqij=1∑m/dqj进一步的整理,把无关的提到最前
然后现在我们会发现,什么都好算了:
- 最后面那两个sigmasigmasigma:就是等差数列求和,设sum(n,m)=(∑i=1ni)(∑j=1mj)sum(n,m)=(\sum\limits_{i=1}^{n}i)(\sum\limits_{j=1}^{m}j)sum(n,m)=(i=1∑ni)(j=1∑mj),显然根据搞死求和公式,它=(n(n+1)2)(m(m+1)2)=(\frac{n(n+1)}{2})(\frac{m(m+1)}{2})=(2n(n+1))(2m(m+1))。后面两个sigmasigmasigma就变成了sum(n/dq,m/dq)sum(n/dq,m/dq)sum(n/dq,m/dq),就珂以O(1)O(1)O(1)求了。
- 如果能求出μ(q)\mu(q)μ(q)的所有值,那么q2μ(q)q^2\mu(q)q2μ(q)的所有值也能求,同时也就能求q2μ(q)q^2\mu(q)q2μ(q)的前缀和。那么∑q=1n/dq2μ(q)∑i=1n/dqi∑j=1m/dqj=∑q=1n/dq2μ(q)s(n/dq,m/dq)\sum\limits_{q=1}^{n/d}q^2\mu(q)\sum\limits_{i=1}^{n/dq}i\sum\limits_{j=1}^{m/dq}j=\sum\limits_{q=1}^{n/d}q^2\mu(q)s(n/dq,m/dq)q=1∑n/dq2μ(q)i=1∑n/dqij=1∑m/dqj=q=1∑n/dq2μ(q)s(n/dq,m/dq)就珂以整除分块了,设其为f(n/d,m/d)f(n/d,m/d)f(n/d,m/d)
- 设了不少函数!现在原式变为∑d=1ndf(n/d,m/d)\sum\limits_{d=1}^{n}df(n/d,m/d)d=1∑ndf(n/d,m/d),这个整除分块太tm^{tm}tm明显了吧!
计算一下时间复杂度。一次f(n/d,m/d)f(n/d,m/d)f(n/d,m/d)最坏是f(n,m)f(n,m)f(n,m),也就是O(n)O(\sqrt{n})O(n)。
外层在套一层整除分块,也就是O(n)O(\sqrt{n})O(n)。
两层一乘,O(n)O(n)O(n)过了。
(而实际上并不是准确的O(n)O(n)O(n),稍微要小一点,应该是O(∑i=1nn/i)O(\sum\limits_{i=1}^{\sqrt{n}}\sqrt{n/i})O(i=1∑nn/i),反正小于O(n)O(n)O(n)就是了。O(n)O(n)O(n)是能过的,我们的代码当然珂以过)
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define mod 20101009
#define N 10000010
namespace Flandle_Scarlet
{
int mu[N],primes[N];
bool notp[N];
int d2mu[N];
//d2mu[i]=i*i*μ(i)的前缀和
void Init()
{
mu[1]=notp[1]=1;
int n=10000000;
int &cnt=primes[0];
for(int i=2;i<=n;++i)//线性筛mu
{
if (!notp[i])
{
primes[++cnt]=i;
mu[i]=-1;
}
for(int j=1;j<=cnt and i*primes[j]<=n;++j)
{
int u=primes[j];
notp[i*u]=1;
if (i%u==0)
{
mu[i*u]=0;
break;
}
else
{
mu[i*u]=-mu[i];
}
}
}
for(int i=1;i<=n;++i)
{
d2mu[i]=(d2mu[i-1]+i*i%mod*(mu[i]+mod))%mod;
//这个式子十分显然,但是注意取膜时的优先级
}
}
int sum(int n,int m)
//也就是上面说的sum
//但是一定要注意优先级!!!我错了好多次!!!
{
return ((n*(n+1)/2)%mod*(m*(m+1)/2)%mod)%mod;
}
int f(int n,int m)
//也就是上面说的f
{
int ans=0;
for(int l=1,r;l<=min(n,m);l=r+1)
{
r=min(n/(n/l),m/(m/l));
//d2mu[r]-d2mu[l-1]计算中间和
//sum(n/l,m/l)是相同部分
ans=(ans+(d2mu[r]-d2mu[l-1]+mod)*sum(n/l,m/l)%mod)%mod;
}
return ans;
}
int calc(int n,int m)
//主求解函数
{
int ans=0;
for(int l=1,r;l<=min(n,m);l=r+1)
{
r=min(n/(n/l),m/(m/l));
//这个太显然了。。。不想解释
ans=(ans+(r-l+1)*(l+r)/2%mod*f(n/l,m/l)%mod)%mod;
}
return ans;
}
int n,m;
void Main()
{
Init();
scanf("%lld%lld",&n,&m);
printf("%lld\n",calc(n,m));
}
};
main()
{
Flandle_Scarlet::Main();
return 0;
}
博客围绕求∑(i=1到n)∑(j=1到m)lcm(i,j)(n,m<=1e7)的问题展开。先给出示例数据,输入4 5输出122。接着采用反演思路推导式子,通过一系列变换和整理,利用等差数列求和、整除分块等方法求解,分析时间复杂度小于O(n)。
684

被折叠的 条评论
为什么被折叠?



