zoukankan      html  css  js  c++  java
  • Loj #2085. 「NOI2016」循环之美

    Loj #2085. 「NOI2016」循环之美

    题目描述

    牛牛是一个热爱算法设计的高中生。在他设计的算法中,常常会使用带小数的数进行计算。牛牛认为,如果在 (k) 进制下,一个数的小数部分是纯循环的,那么它就是美的。

    现在,牛牛想知道:对于已知的十进制数 (n)(m),在 (k) 进制下,有多少个数值上互不相等的纯循环小数,可以用分数 (frac x y) 表示,其中 (1le xle n,1le yle m),且 (x,y) 是整数。

    一个数是纯循环的,当且仅当其可以写成以下形式:

    [a.dot{c_1} c_2 c_3 ldots c_{p - 1} dot{c_p} ]

    其中,(a) 是一个整数,(pge1);对于 (1le ile p)(c_i)(k) 进制下的一位数字。

    例如,在十进制下,(0.45454545dots=0.dot{4}dot{5}) 是纯循环的,它可以用 (frac 5 {11})(frac{10}{22}) 等分数表示;在十进制下,(0.1666666dots=0.1dot{6}) 则不是纯循环的,它可以用 (frac 1 6) 等分数表示。

    需要特别注意的是,我们认为一个整数是纯循环的,因为它的小数部分可以表示成 (0) 的循环或是 (k-1) 的循环;而一个小数部分非 (0) 的有限小数不是纯循环的。

    输入格式

    输入文件只有一行,包含三个十进制数 (n,m,k),意义如题所述。

    输出格式

    只输出一行一个整数,表示满足条件的美的数的个数。

    数据范围与提示

    对于所有的测试点,保证 (1le nle 10^9)(1le mle 10^9)(2le kle2000)


    首先有个结论就是,如果(frac{x}{y} gcd(x,y)=1)是个在(k)进制意义下是纯循环小数,那么(gcd(y,k)=1)

    所以:

    [egin{align} ans&=sum_{i=1}^nsum_{j=1}^m[gcd(i,j)=1][gcd(j,k)=1]\ &=sum_{i=1}^nsum_{j=1}^m[gcd(j,k)=1]sum_{d|i,d|j}mu(d) end{align} ]

    因为(gcd(j,k)=1,d|j),所以(gcd(d,k)=1)

    [egin{align} ans&=sum_{gcd(d,k)=1}mu(d)sum_{i=1}^{lfloorfrac{n}{d} floor}sum_{j=1}^{lfloorfrac{m}{d} floor}[gcd(j,k)=1]\ &=sum_{gcd(d,k)=1}mu(d)lfloorfrac{n}{d} floor sum_{j=1}^{lfloorfrac{m}{d} floor}[gcd(j,k)=1]\ end{align} ]

    这就是一个整除分块的形式了。但是我们还要求出一下两个函数才能求出答案。

    [f(n,k)=sum_{i=1}^n[gcd(i,k)=1] ]

    [S(n,k)=sum_{i=1}^n[gcd(i,k)=1]mu(i) ]

    先看(f)。因为(gcd(i,k)=gcd(i+k,k)),所以没(k)段中,与(k)的互质的数的个数都是相同的。我们先预处理出(f(1ldots k,k))的值,那么(f(n,k)=lfloor frac{n}{k} floor f(k,k)+f(n\%k,k))

    再来看(S)

    [S(n,k)=sum_{i=1}^n[gcd(i,k)=1]mu(i)\ =sum_{i=1}^nmu(i)sum_{d|i,d|k}mu(d)\ =sum_{d|k}mu(d)sum_{i=1}^{lfloorfrac{n}{d} floor}mu(i*d) ]

    又因为,(gcd(i,d)!=1)时,(mu(i*d)=0),所以:

    [egin{align} S(n,k)&=sum_{d|k}mu(d)sum_{i=1,gcd(i,d)=1}^{lfloorfrac{n}{d} floor}mu(i*d)\ &=sum_{d|k}mu(d)^2sum_{i=1}^{lfloorfrac{n}{d} floor}[gcd(i,d)=1]mu(i)\ &=sum_{d|k}mu(d)^2S(lfloorfrac{n}{d} floor,d) end{align} ]

    于是可以递归求(S)。当递归到(k=1)时,答案就是(mu)的前缀和,这个用杜教筛就可以了。

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    #define K 2005
    #define maxx 1000005
    
    using namespace std;
    inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
    
    int n,m,k;
    int gcd(int a,int b) {return !b?a:gcd(b,a%b);}
    ll ans;
    ll f[K];
    int pr[maxx],vis[maxx];
    ll u[maxx];
    void pre(int n) {
    	u[1]=1;
    	for(int i=2;i<=n;i++) {
    		if(!vis[i]) pr[++pr[0]]=i,u[i]=-1;
    		for(int j=1;j<=pr[0]&&1ll*i*pr[j]<=n;j++) {
    			vis[i*pr[j]]=1;
    			if(i%pr[j]==0) {
    				u[i*pr[j]]=0;
    				break;
    			}
    			u[i*pr[j]]=-u[i];
    		}
    	}
    	for(int i=1;i<=n;i++) u[i]+=u[i-1];
    }
    
    map<ll,int>st;
    ll Sum(ll n) {
    	if(n<=1e6) return u[n];
    	if(st.find(n)!=st.end()) return st[n];
    	ll ans=1;
    	ll last=2,now;
    	for(;last<=n;last=now+1) {
    		now=n/(n/last);
    		ans-=(now-last+1)*Sum(n/last);
    	}
    	return st[n]=ans;
    }
    
    ll cal_f(int n) {return n/k*f[k]+f[n%k];}
    map<ll,ll>S[K];
    ll cal_S(int n,int k) {
    	if(!n) return 0;
    	if(S[k].find(n)!=S[k].end()) return S[k][n];
    	if(k==1) return S[k][n]=Sum(n);
    	ll ans=0;
    	for(int d=1;d<=k;d++) {
    		if(k%d) continue ;
    		ans+=(u[d]-u[d-1])*(u[d]-u[d-1])*cal_S(n/d,d);
    	}
    	return S[k][n]=ans;
    }
    
    int main() {
    	pre(1e6);
    	n=Get(),m=Get(),k=Get();
    	for(int i=1;i<=k;i++) f[i]=f[i-1]+(gcd(i,k)==1);
    	ll now,last=1;
    	ll ans=0;
    	for(int lim=min(n,m);last<=lim;last=now+1) {
    		now=min(n/(n/last),m/(m/last));
    		ans+=(cal_S(now,k)-cal_S(last-1,k))*(n/last)*cal_f(m/last);
    	}
    	cout<<ans;
    	return 0;
    }
    
    
  • 相关阅读:
    javascript 的继承实例
    [转载]编写高性能js
    弹出菜单
    xml xpath dta笔记
    jquery 学习笔记
    公用的css
    谷歌主页动画效果——利用视距暂留原理
    javascript 新知识
    ie6/7 bug大全
    javascript 原生实现 jquery live/delegate
  • 原文地址:https://www.cnblogs.com/hchhch233/p/10949567.html
Copyright © 2011-2022 走看看