题目
Description
Input
Output
Sample Input
2
10 10 0
10 10 1
Sample Output
63
93
Data Constraint
题解
不妨设n<m
令
q
(
l
i
m
,
n
)
=
1
q(lim,n)=1
q(lim,n)=1表示n的质因数个数不大于lim,
q
(
l
i
m
,
n
)
=
0
q(lim,n)=0
q(lim,n)=0表示n的质因数个数大于lim。
显然题目要我们求的是
∑
i
=
1
n
∑
j
=
1
m
q
(
g
c
d
(
i
,
j
)
,
l
i
m
)
\sum_{i=1}^n\sum_{j=1}^m q(gcd(i,j),lim)
i=1∑nj=1∑mq(gcd(i,j),lim)这样直接暴力做是只有30分的,因此考虑化简。
∑
i
=
1
n
∑
j
=
1
m
q
(
g
c
d
(
i
,
j
)
,
l
i
m
)
=
∑
d
=
1
n
q
(
d
,
l
i
m
)
∑
i
=
1
⌊
n
d
⌋
∑
j
=
1
⌊
m
d
⌋
[
g
c
d
(
i
,
j
)
=
1
]
把gcd提前
=
∑
d
=
1
n
q
(
d
,
l
i
m
)
∑
i
=
1
⌊
n
d
⌋
∑
j
=
1
⌊
m
d
⌋
∑
p
∣
i
,
p
∣
j
μ
(
p
)
下文会解释
=
∑
d
=
1
n
q
(
d
,
l
i
m
)
∑
p
=
1
⌊
n
d
⌋
μ
(
p
)
⌊
⌊
n
d
⌋
p
⌋
⌊
⌊
m
d
⌋
p
⌋
=
∑
d
=
1
n
q
(
d
,
l
i
m
)
∑
p
=
1
⌊
n
d
⌋
μ
(
p
)
⌊
n
p
d
⌋
⌊
m
p
d
⌋
下文会解释
\begin{aligned} &\sum_{i=1}^n\sum_{j=1}^m q(gcd(i,j),lim)\\ =&\sum_{d=1}^n q(d,lim)\sum_{i=1}^{\left\lfloor\frac{n}{d}\right\rfloor}\sum_{j=1}^{\left\lfloor\frac{m}{d}\right\rfloor}[gcd(i,j)=1]&\text{把gcd提前}\\ =&\sum_{d=1}^n q(d,lim)\sum_{i=1}^{\left\lfloor\frac{n}{d}\right\rfloor}\sum_{j=1}^{\left\lfloor\frac{m}{d}\right\rfloor}\sum_{p|i,p|j}\mu(p)&\text{下文会解释}\\ =&\sum_{d=1}^n q(d,lim)\sum_{p=1}^{\left\lfloor\frac{n}{d}\right\rfloor}\mu(p)\left\lfloor\cfrac{\left\lfloor\frac{n}{d}\right\rfloor}{p}\right\rfloor\left\lfloor\cfrac{\left\lfloor\frac{m}{d}\right\rfloor}{p}\right\rfloor\\ =&\sum_{d=1}^n q(d,lim)\sum_{p=1}^{\left\lfloor\frac{n}{d}\right\rfloor}\mu(p)\left\lfloor\frac{n}{pd}\right\rfloor\left\lfloor\frac{m}{pd}\right\rfloor&\text{下文会解释} \end{aligned}
====i=1∑nj=1∑mq(gcd(i,j),lim)d=1∑nq(d,lim)i=1∑⌊dn⌋j=1∑⌊dm⌋[gcd(i,j)=1]d=1∑nq(d,lim)i=1∑⌊dn⌋j=1∑⌊dm⌋p∣i,p∣j∑μ(p)d=1∑nq(d,lim)p=1∑⌊dn⌋μ(p)⌊p⌊dn⌋⌋⌊p⌊dm⌋⌋d=1∑nq(d,lim)p=1∑⌊dn⌋μ(p)⌊pdn⌋⌊pdm⌋把gcd提前下文会解释下文会解释
先来解释一下上面的化简步骤。
先是第二步:
设 h i h_i hi表示 i 是x,y公因数的对数。
那么两两互质的就有 h 1 − h 2 − h 3 + h 6 − h 5 ⋯ h_1-h_2-h_3+h_6-h_5\cdots h1−h2−h3+h6−h5⋯个。
是不是很像莫比乌斯反演?
再解释最后一步:
取整函数有一个有趣的性质: ⌊ ⌊ n a ⌋ b ⌋ = ⌊ n a b ⌋ \left\lfloor\cfrac{\left\lfloor\frac{n}{a}\right\rfloor}{b}\right\rfloor=\left\lfloor\cfrac{n}{ab}\right\rfloor ⌊b⌊an⌋⌋=⌊abn⌋
证明不难。
设
b
=
p
d
b=pd
b=pd,那么又可以进一步变形了(下面的大括号表示解决方法)
=
∑
b
=
1
n
⌊
n
p
d
⌋
⌊
m
p
d
⌋
⎵
数论分块
∑
d
∣
b
q
(
d
,
l
i
m
)
μ
(
b
d
)
⎵
前缀和
=\underbrace{\sum_{b=1}^n \left\lfloor\frac{n}{pd}\right\rfloor\left\lfloor\frac{m}{pd}\right\rfloor}_{\text{数论分块}}\underbrace{\sum_{d|b}q(d,lim)\mu\left(\frac{b}{d}\right)}_{\text{前缀和}}
=数论分块
b=1∑n⌊pdn⌋⌊pdm⌋前缀和
d∣b∑q(d,lim)μ(db)
数论分块可以看这里
前缀和的话令
S
(
n
,
l
i
m
)
=
∑
i
=
1
n
∑
d
∣
n
q
(
d
,
l
i
m
)
μ
(
n
d
)
S(n,lim)=\sum_{i=1}^n\sum_{d|n}q(d,lim)\mu\left(\frac{n}{d}\right)
S(n,lim)=∑i=1n∑d∣nq(d,lim)μ(dn)
然后枚举一个L,再枚举刚好有L个质因数的数 i ,枚举 i 的每一个倍数 j ,把
S
(
j
,
L
)
S(j,L)
S(j,L)加上
μ
(
j
i
)
\mu(\frac{j}{i})
μ(ij)
然后处理询问就可以了。
水法
看这条式子
∑
d
=
1
n
q
(
d
,
l
i
m
)
∑
p
=
1
⌊
n
d
⌋
μ
(
p
)
⌊
n
p
d
⌋
⌊
m
p
d
⌋
\sum_{d=1}^n q(d,lim)\sum_{p=1}^{\left\lfloor\frac{n}{d}\right\rfloor}\mu(p)\left\lfloor\frac{n}{pd}\right\rfloor\left\lfloor\frac{m}{pd}\right\rfloor
d=1∑nq(d,lim)p=1∑⌊dn⌋μ(p)⌊pdn⌋⌊pdm⌋
可以把莫比乌斯函数用前缀和维护(直接暴力加起来),后面的整除数论分块。
然后暴力
O
(
n
p
n
)
O(np\sqrt{n})
O(npn)乱搞,显然TLE。
怎么办呢?考虑分类讨论:
- 当 P ≤ 3 P\leq3 P≤3时,暴力做不会时超。
- 当 P > 3 P>3 P>3时,把不符合条件的p给删掉,剩下的就是符合条件的了。
于是就可以600+ms水过去了。
CODE
正解:
#include<cstdio>
#include<cstring>
using namespace std;
#define ll long long
#define N 500005
ll prime[50000],u[N],f[N],s[N][20],a[N],nex[N],fir[N];
bool b[N];
inline ll mymin(ll x,ll y){return x<y?x:y;}
int main()
{
ll n,m,lim,i,j,k,t,l,r,ans=0;
u[1]=1,f[1]=0,fir[0]=1;
for(i=2;i<N;i++)
{
if(!b[i]) prime[++prime[0]]=i,f[i]=1,u[i]=-1;
for(j=1;j<=prime[0]&&i*prime[j]<N;j++)
{
b[i*prime[j]]=1;
f[i*prime[j]]=f[i]+1;
if(i%prime[j]==0) break;
u[i*prime[j]]=-u[i];
}
nex[i]=fir[f[i]],fir[f[i]]=i;
}
for(j=0;j<19;j++)
{
for(i=fir[j];i;i=nex[i])
for(k=i;k<N;k+=i)
a[k]+=u[k/i];
for(i=1;i<N;i++)
s[i][j]=s[i-1][j]+a[i];
}
scanf("%lld",&t);
while(t--)
{
scanf("%lld%lld%lld",&n,&m,&lim);
lim=mymin(lim,19);
if(n>m) n^=m,m^=n,n^=m;
if(1ll<<lim>n){printf("%lld\n",n*m);continue;}
l=1,ans=0;
while(l<=n)
{
r=mymin(n/(n/l),m/(m/l));
ans+=n/l*(m/l)*(s[r][lim]-s[l-1][lim]);
l=r+1;
}
printf("%lld\n",ans);
}
return 0;
}
水法:
//摘自DL蔑蔑
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#define ll long long
using namespace std;
int su[100010],mu[500010],chun[500010],qian[500010];
bool b[500010];
int FY(int n,int m,int p)
{
int re=0;
if (n>m) swap(n,m);
n/=p;
m/=p;
for (int i=1;i<=n;i++)
{
int ii=min(n/(n/i),m/(m/i));
re+=(qian[ii]-qian[i-1])*(n/i)*(m/i);
i=ii;
}
return re;
}
int main()
{
mu[1]=1;
chun[1]=0;
for (int i=2;i<=500000;i++)
{
if (!b[i])
{
su[++su[0]]=i;
mu[i]=-1;
chun[i]=1;
}
for (int j=1;j<=su[0];j++)
if (i*su[j]<=500000)
{
b[i*su[j]]=true;
chun[i*su[j]]=chun[i]+1;
if (i%su[j]==0)
{
mu[i*su[j]]=0;
break;
}
else mu[i*su[j]]=-mu[i];
}
else break;
}
for (int i=1;i<=50000;i++)
qian[i]=qian[i-1]+mu[i];
int T;
scanf("%d",&T);
while (T--)
{
int n,m,fw,ans=0;
scanf("%d%d%d",&n,&m,&fw);
if (fw>=19)
{
printf("%lld\n",(ll)n*(ll)m);
continue;
}
int nn=min(n,m);
if (fw<3)
{
for (int p=1;p<=nn;p++)
if (chun[p]<=fw)
{
ans+=FY(n,m,p);
}
printf("%d\n",ans);
}
else
{
ll lans=(ll)n*(ll)m;
for (int p=1;p<=nn;p++)
if (chun[p]>fw)
{
lans-=(ll)FY(n,m,p);
}
printf("%lld\n",lans);
}
}
}