题意
问 (k) 进制下,分子为 ([1,n]),分母为 ([1,m]) 的纯循环小数有多少个(值相同算同一个)。(n,mleq 10^9),(kleq 2000)。
题解
根据我们小学二年级就学过的结论,对于 (k) 进制下的最简分数 (dfrac{x}{y}) 是纯循环小数,当且仅当 (yot k)。于是问题变为:
[egin{aligned}
&sum_{i=1}^{n}sum_{j=1}^{n}[iot j][jot k]\
=&sum_{j=1}^{m}[jot k]sum_{j=1}^{n}[iot j]\
=&sum_{j=1}^{m}[jot k]sum_{j=1}^{n}sum_{d|gcd(i,j)}mu d\
=&sum_{d=1}^{n}[dot k]mu(d)sum_{j=1}^{m /d}sum_{i=1}^{n /d}[jot k]\
=&sum_{d=1}^{n}[dot k]mu(d)lfloor dfrac{n}{d}
floorsum_{j=1}^{m /d}[jot k]
end{aligned}
]
设
-
[f(x)=sum_{i=1}^x[iot k] ]
- 由于 ([iot k]) 是 (f) 个一循环的,预处理 (f(1..k)) 后容易计算。
-
[g(x,k)=sum_{i=1}^x[iot k]mu(i) ]
[egin{aligned}
g(x,k)=&sum_{i=1}^x[iot k]mu(i)\
=&sum_{i=1}^xmu(i)sum_{i|d}mu(i)\
=&sum_{d|k}^{x}mu(d)sum_{i|d}mu(i)\
=sum_{d|k}^{x}mu(d)sum_{p=1}^{x /d}mu(pd)
end{aligned}
]
当 (p ot ot d),(mu(pd)=0)。我们继续:
[egin{aligned}
g(x,k)=&sum_{d|k}^{x}mu^2(d)sum_{p=1}^{x /d}[pot d]\
=&sum_{d|k}^{x}[mu(d)
eq 0]sum_{p=1}^{x /d}mu(p)[pot d]\
=&sum_{d|k}^{x}[mu(d)
eq 0]g(lfloor dfrac{n}{d}
floor,d)
end{aligned}
]
递归计算,(g(n,1)) 为 (mu) 的前缀和。
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
int getint(){
int ans=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
ans=ans*10+c-'0';
c=getchar();
}
return ans*f;
}
#define ll long long
const int M=2e6,N=1e9;
int pri[M+1],mu[M+1],cnt=0;
bool vis[M+1],v[M];
unordered_map<int,int> mu2;
int n,m,k;
int f_[M];
int gcd(int x,int y){ return x?gcd(y%x,x):y; }
int f(int x){
return f_[k]*(x/k)+f_[x%k];
}
int get_mu(int x){
//f=mu,g=I,f*g=e
if(x<=M)return mu[x];
if(mu2.count(x))return mu2[x];
ll ans=bool(x);
for(int i=2,j;j<x&&i<=x;i=j+1){
j=x/(x/i);
ans-=(j+1ll-i)*get_mu(x/i);
}
return mu2[x]=ans;
}
ll g(int x,int k){
if(k==1)return get_mu(x);
if(!x)return 0;
ll ans=0;
for(int i=1;i*i<=k;i++){
if(k%i)continue;
if(x>=i&&mu[i]-mu[i-1])ans=ans+g(x/i,i);
if(x>=k/i&&(mu[k/i]-mu[k/i-1])&&i*i!=k)ans=ans+g(x/(k/i),k/i);
}
return ans;
}
int main(){
mu[1]=1;
for(int i=2;i<=M;i++){
if(!vis[i])pri[cnt++]=i,mu[i]=-1;
for(int j=0;j<cnt&&i*pri[j]<=M;j++){
vis[i*pri[j]]=1;
if(i%pri[j])mu[i*pri[j]]=-mu[i];
else break;
}
mu[i]+=mu[i-1];
}
n=getint(),m=getint(),k=getint();
for(int i=1;i<=k;i++)f_[i]=f_[i-1]+(gcd(i,k)==1);
ll ans=0;
for(ll l=1,r,sl=0;l<=min(n,m);l=r+1){
r=min(n/(n/l),m/(m/l));
int p=n/l,q=m/l;
ll sr=g(r,k);
ans+=(sr-sl)*p*f(q);
sl=sr;
}
cout<<ans<<endl;
return 0;
}