题意简述
(本题时限121212秒,空间512MB512MB512MB,这很大,注意)。有一个女孩问你,给你n,m(n,m<=107)n,m(n,m<=10^7)n,m(n,m<=107),如果你能121212秒内求出∑i=1n∑j=1mf(i,j)\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}f(i,j)i=1∑nj=1∑mf(i,j)(其中f(i,j)f(i,j)f(i,j)当gcd(i,j)gcd(i,j)gcd(i,j)为平方数时是000,否则是111)。如果你能求出来,她就是你女朋友了QωQQ\omega QQωQ(如果不嫌弃的话珂以找我来当女友。。。我是个珂爱的女孩子呢。。。)
多组数据。数据组数<=104<=10^4<=104
数据
输入
2
1 2333333
10 10
输出
0
33
思路
这个题一看就是一个莫比乌斯反演题。那么,也没什么好说的,开始推式子吧QωQQ\omega QQωQ。
首先,能做这个题目的人,肯定会这个式子(这个都不会,下面估计看不懂。。。别急,去我的博客找莫比乌斯反演的那篇,在"LightningUZ の 学习笔记"里有)。
为了方便,设gcd(i,j)=ggcd(i,j)=ggcd(i,j)=g,⌊ab⌋=a/b\lfloor\frac{a}{b}\rfloor=a/b⌊ba⌋=a/b,并且不妨令n<=mn<=mn<=m。则有:
∑i=1n∑j=1m[g==d]=∑q=1n/dμ(q)(n/q)(m/q)\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}[g==d]=\sum\limits_{q=1}^{n/d}\mu(q)(n/q)(m/q)i=1∑nj=1∑m[g==d]=q=1∑n/dμ(q)(n/q)(m/q)。
这是十分基础的莫比乌斯反演。
接下来,我们改一下fff的定义,令f(x)=[x∈square]f(x)=[x\in square]f(x)=[x∈square](和题面给出的fff正好相反),那么原式=nm−∑i=1n∑j=1mf(g)=nm-\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}f(g)=nm−i=1∑nj=1∑mf(g)(求一下补集即可,因为fff反了)。nmnmnm都会求(入门难度),难的就是后面那两个sigmasigmasigma。
怎么求呢?首先,我们把ggg放前面枚举,原式
=∑d=1nf(d)∑i=1n∑j=1m[g==d]=\sum\limits_{d=1}^{n}f(d)\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}[g==d]=d=1∑nf(d)i=1∑nj=1∑m[g==d]
根据f(d)f(d)f(d)的定义(上面提到了那个重定义),记sqr=sqr=sqr=平方数集合,原式
=∑d∈sqr∑i=1n∑j=1m[g=d]=\sum\limits_{d\in sqr}\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}[g=d]=d∈sqr∑i=1∑nj=1∑m[g=d]
=∑d∈sqr∑q=1n/dμ(q)(n/dq)(m/dq)=\sum\limits_{d\in sqr}\sum\limits_{q=1}^{n/d}\mu(q)(n/dq)(m/dq)=d∈sqr∑q=1∑n/dμ(q)(n/dq)(m/dq)
设T=dqT=dqT=dq,我们把ddd和qqq放一块枚举。原式
=∑d∈sqr∑q=1n/dμ(q)(n/T)(m/T)=\sum\limits_{d\in sqr}\sum\limits_{q=1}^{n/d}\mu(q)(n/T)(m/T)=d∈sqr∑q=1∑n/dμ(q)(n/T)(m/T)
=∑T=1n(n/T)(m/T)∑d∈sqr,d∣Tμ(Tk)=\sum\limits_{T=1}^{n}(n/T)(m/T)\sum\limits_{d\in sqr,d|T} \mu(\frac{T}{k})=T=1∑n(n/T)(m/T)d∈sqr,d∣T∑μ(kT)
这一步就是先枚举了T,然后去后面找哪些q会算到T这一步就是先枚举了T,然后去后面找哪些q会算到T这一步就是先枚举了T,然后去后面找哪些q会算到T
到这里就结束了??不过说实话,好像还真的没有思路继续下去了。但是我们有一个梦想(做数学题一定要有梦想),我们要是能O(1)O(1)O(1)求∑d∈sqr,d∣Tμ(Tk)\sum\limits_{d\in sqr,d|T} \mu(\frac{T}{k})d∈sqr,d∣T∑μ(kT)就好了。(这个式子设为g(T)g(T)g(T))
我们仔细想想,发现,我们只要枚举一个平方数,枚举倍数,加上μ\muμ值,预处理出来,好像真的珂以O(1)O(1)O(1)求!!!
那代码就出来了。
代码:
#include<bits/stdc++.h>
#define N 10010000//时限大+空间大=随便浪
using namespace std;
namespace Flandle_Scarlet//最近喜欢这么写
{
#define int long long
int primes[N],mu[N],g[N];
bool notp[N];
//g[n]=sigma(d is square and d|n) mu(x/d)
void Init()//预处理μ和我们推出来珂以预处理的那一部分(设为g(T))
{
notp[1]=mu[1]=1;
int n=10000000;
int &cnt=primes[0];
for(int i=2;i<=n;++i)
{
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];
}
}
}//处理好mu
for(int tmp=1;tmp*tmp<=n;++tmp)
{
int d=tmp*tmp;//枚举一个平方数
for(int j=1;j*d<=n;++j)//j枚举倍数
{
g[j*d]+=mu[j];//加上mu[j]
}
}
for(int i=1;i<=n;++i)
{
g[i]+=g[i-1];//处理前缀和
}
}
int n,m;
void Solve()//肥肠水的分块
{
if (n>m) n^=m^=n^=m;
int ans=0;
for(int l=1,r;l<=n;l=r+1)
{
r=min(n/(n/l),m/(m/l));
ans+=(n/l)*(m/l)*(g[r]-g[l-1]);
}
printf("%lld\n",n*m-ans);
}
void Main()
{
Init();
int T;
scanf("%lld",&T);
while(T--)
{
scanf("%lld%lld",&n,&m);
Solve();
}
}
#undef int//记得undef掉,然后后面就珂以开开心心的int main()了
}
int main()
{
Flandle_Scarlet::Main();
return 0;
}
本文详细解析了一个涉及莫比乌斯反演的数学问题,通过巧妙的数学变换,将原问题转化为可高效求解的形式。特别地,文章提供了完整的推导过程及代码实现,展示了如何在限定时间内解决大规模数据问题。
1233

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



