zoukankan      html  css  js  c++  java
  • HDU 2588 GCD(欧拉函数)

    思路:

    1.题意是给出nnmm,让我们找出有多少个x(1<=x<=n)x(1<=x<=n)满足gcd(n,x)>=mgcd(n,x)>=m
    2.设nnxx的最大公约数是dd,则我们可以将nnxx表示成
    {n=pdx=qd egin{cases} n=p*d\ x=q*d end{cases}
    且我们可以得知ppqq互质且q<=pq<=p,因此我们需要求出在此时dd确定的情况下有多少个qq存在即可,即求pp的欧拉函数;
    3.接着我们的目标就是求出对于每一个d(d>=m)d(d>=m),与之对应的pp的欧拉函数,最后将它们相加即可;
    4.可能有些人会有疑问(比如说我),题目问xx有多少种取值,我们就简单的遍历所有pp,将这些pp的欧拉函数相加就好了吗?不同的dd对应不同的pp,而同一个pp也对应许多不同的qq,有没有可能这些情况中,计算出来的xx值有重复?
    答案是不会的。我们来证明一下,假设
    {n=p1d1x1=q1d1n=p2d2x2=q2d2x1=x2 egin{cases} n=p1*d1\ x1=q1*d1\ n=p2*d2\ x2=q2*d2\ x1=x2 end{cases}
    则会有
    {p1d1=p2d2q1d1=q2d2 egin{cases} p1*d1=p2*d2\ q1*d1=q2*d2 end{cases}
    则有p1=p2q1q2p1=frac{p2*q1}{q2},此时q1q2q1 eq q2,因此必有q1q1的一个或多个质因子包含在p1p1中,这与q1p1q1p1互质相矛盾,因此xx的值不会重复;

    代码:

    #include<iostream>
    #include<vector>
    using namespace std;
    int n,m;
    vector<int> v;
    void cal_divisor(int n){  //which is greater than m or equals to m
    	for(int i=1;i*i<=n;i++) if(n%i==0){
    			if(i>=m) v.push_back(i);
    			if(i!=n/i&&n/i>=m) v.push_back(n/i); 
    	}
    }
    int eular(int n){
    	int ans=n;
    	for(int i=2;i*i<=n;i++) if(n%i==0){
    		ans-=ans/i;
    		while(n%i==0) n/=i;
    	}
    	if(n>1) ans-=ans/n;
    	return ans;
    }
    int solve(){
    	if(m==1) return n;
    	v.clear();
    	cal_divisor(n);
    	int ans=0;
    	for(auto x:v) ans+=eular(n/x);
    	return ans;
    }
    int main(){
    	int t; cin>>t;
    	while(t--){
    		cin>>n>>m;
    		cout<<solve()<<'
    ';
    	}
    	return 0;
    }
    
  • 相关阅读:
    最小生成数kruskal算法和prim算法
    图的表示及遍历
    mysql忘记root用户密码重置密码的方式
    dwr2.0版本的demo
    web.xml中不同版本的servlet头以及版本控制
    初学jboss
    Filter学习总结,顺便提及点servlet3.0异步filter和异步监听
    监听器
    问题发现和解决
    linux学习
  • 原文地址:https://www.cnblogs.com/yuhan-blog/p/12308790.html
Copyright © 2011-2022 走看看