几年没写题解来更一篇。
首先有一个规律就是如果满足条件那么
gcd(y,k)=1
那么答案就是
∑i=1n∑j=1m[gcd(i,j)=1][gcd(j,k)=1]
=∑j=1m[gcd(j,k)=1]∑i=1n∑t|i,t|jμ(t)
=∑t=1mμ(t)∗⌊nt⌋∑j=1mt[gcd(tj,k)=1]
==∑t=1mμ(t)∗⌊⌊nt⌋⌋[gcd(t,k)=1]∑j=1⌊mt⌋[gcd(j,k)=1]
O(n√)
枚举
⌊nt⌋,⌊mt⌋
对于每段
∑j=1x[gcd(j,k)=1]=∑r|kμ(r)∗⌊xr⌋
直接算就行了。
设k的质因数分解为
pa11pa22....pacntcnt
,
ki=pa11pa22....paii
设
f(i,x)=∑t=1xμ(t)[gcd(t,ki)=1]
那么要求的是
f(cnt,x)
f(i,x)=∑t=1xμ(t)[gcd(t,ki)=1]
=∑t=1xμ(t)[gcd(t,ki−1paii)=1]
=∑t=1xμ(t)[gcd(t,ki−1)=1][gcd(t,pi)=1]
=∑t=1xμ(t)[gcd(t,ki−1)=1]−∑pi|tμ(t)[gcd(t,ki−1)=1]
=∑t=1xμ(t)[gcd(t,ki−1)=1]−∑t=1⌊xpi⌋μ(t∗pi)[gcd(t∗pi,ki−1)=1]
=∑t=1xμ(t)[gcd(t,ki−1)=1]−∑t=1⌊xpi⌋μ(t∗pi)[gcd(t,ki)=1]
然后第二段中如果
t%pi=0
没有贡献,否则当
gcd(t,pi)=1
时
μ(t∗pi)=−μ(t)
因此上式
=∑t=1xμ(t)[gcd(t,ki−1)=1]+∑t=1⌊xpi⌋μ(t)[gcd(t,ki)=1]
=f(i−1,x)+f(i,⌊xpi⌋)
当
i=0
时
f(i,x)
可以通过杜教筛计算。
然后这个杜教筛就是把
∑i=1⌊nx⌋μ(i)
算一遍。
因此复杂度大概是
O(min(n,m)−−−−−−−−√∗(k√+logn)+n23logn)
Orz 小火车
#include <bits/stdc++.h>
using namespace std;
#define N 5100000
#define A 5000000
#define ll long long
ll ans;
int n,m,K,cnt,cnt1;
int mu[N],prime[N],ip[N],sum[N],p[11],p1[110];
map<pair<int,int>,int>ma1;
map<int,int>ma2;
void init()
{
mu[1]=1;
for(int i=2;i<=A;i++)
{
if(!ip[i]){prime[++cnt]=i;mu[i]=-1;}
for(int j=1;j<=cnt&&i*prime[j]<=A;j++)
{
ip[i*prime[j]]=1;
if(i%prime[j]==0)break;
mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<=A;i++)
sum[i]=sum[i-1]+mu[i];
cnt=0;
for(int i=1;i<=K;i++)
if(K%i==0)p1[++cnt1]=i;
for(int i=1;prime[i]<=K;i++)
if(K%prime[i]==0)p[++cnt]=prime[i];
}
int djs(int x)
{
if(x<=A)return sum[x];
if(ma2.count(x))return ma2[x];
int ret=1;
for(int i=2,last;i<=x;i=last+1)
{
last=x/(x/i);
ret-=djs(x/i)*(last-i+1);
}
return ma2[x]=ret;
}
int cal1(int x,int y)
{
if(y==0)return 0;
if(x==0)return djs(y);
pair<int,int> t=make_pair(x,y);
if(ma1.count(t))return ma1[t];
int ret=cal1(x-1,y)+cal1(x,y/p[x]);
return ma1[t]=ret;
}
int cal2(int x)
{
int ret=0;
for(int i=1;i<=cnt1;i++)
ret+=mu[p1[i]]*(x/p1[i]);
return ret;
}
int main()
{
scanf("%d%d%d",&n,&m,&K);
init();
for(int i=1,last;i<=m&&i<=n;i=last+1)
{
last=min(n/(n/i),m/(m/i));
ans+=(ll)(cal1(cnt,last)-cal1(cnt,i-1))*(n/i)*cal2(m/i);
}
printf("%lld\n",ans);
return 0;
}