zoukankan      html  css  js  c++  java
  • 【题解】LOJ #2085 / 洛谷 P1587「NOI2016」循环之美【莫比乌斯反演】

    题目链接

    题目链接

    题意

    (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;
    }
    
    
    知识共享许可协议
    若文章内无特别说明,公开文章采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
  • 相关阅读:
    CCF|学生排队|Java
    CCF|分蛋糕|Java
    CCF|公共钥匙盒|Java
    CCF|打酱油|Java
    CCF|游戏|Java
    CCF|最小差值|Java
    CCF|路径解析|Java
    CCF|碰撞的小球
    CCF|跳一跳
    Win10 1803更新UWP无法安装的解决办法|错误代码0x80073D0D
  • 原文地址:https://www.cnblogs.com/wallbreaker5th/p/14187660.html
Copyright © 2011-2022 走看看