【题解】LOJ #2085 / 洛谷 P1587「NOI2016」循环之美【莫比乌斯反演】

题目链接

题目链接

题意

\(k\) 进制下,分子为 \([1,n]\),分母为 \([1,m]\) 的纯循环小数有多少个(值相同算同一个)。\(n,m\leq 10^9\)\(k\leq 2000\)

题解

根据我们小学二年级就学过的结论,对于 \(k\) 进制下的最简分数 \(\dfrac{x}{y}\) 是纯循环小数,当且仅当 \(y\bot k\)。于是问题变为:

\[\begin{aligned} &\sum_{i=1}^{n}\sum_{j=1}^{n}[i\bot j][j\bot k]\\ =&\sum_{j=1}^{m}[j\bot k]\sum_{j=1}^{n}[i\bot j]\\ =&\sum_{j=1}^{m}[j\bot k]\sum_{j=1}^{n}\sum_{d|\gcd(i,j)}\mu d\\ =&\sum_{d=1}^{n}[d\bot k]\mu(d)\sum_{j=1}^{m /d}\sum_{i=1}^{n /d}[j\bot k]\\ =&\sum_{d=1}^{n}[d\bot k]\mu(d)\lfloor \dfrac{n}{d}\rfloor\sum_{j=1}^{m /d}[j\bot k] \end{aligned} \]

  • \[f(x)=\sum_{i=1}^x[i\bot k] \]

    • 由于 \([i\bot k]\)\(f\) 个一循环的,预处理 \(f(1..k)\) 后容易计算。
  • \[g(x,k)=\sum_{i=1}^x[i\bot k]\mu(i) \]

\[\begin{aligned} g(x,k)=&\sum_{i=1}^x[i\bot k]\mu(i)\\ =&\sum_{i=1}^x\mu(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\not \bot d\)\(\mu(pd)=0\)。我们继续:

\[\begin{aligned} g(x,k)=&\sum_{d|k}^{x}\mu^2(d)\sum_{p=1}^{x /d}[p\bot d]\\ =&\sum_{d|k}^{x}[mu(d)\neq 0]\sum_{p=1}^{x /d}\mu(p)[p\bot d]\\ =&\sum_{d|k}^{x}[mu(d)\neq 0]g(\lfloor \dfrac{n}{d}\rfloor,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;
}

posted @ 2020-12-25 10:22  破壁人五号  阅读(102)  评论(0编辑  收藏  举报