POJ1284 2773 2478 3090 3358 简单欧拉函数5题

POJ 1284:给一个数奇质数P,求P的原根个数

设m是正整数,a是整数,若a模m的阶等于φ(m),则称a为模m的一个原根。(其中φ(m)表示m的 欧拉函数
假设一个数g对于P来说是原根,那么g^i mod P的结果两两不同,且有 1<g<P, 0<i<P,那么g可以称为是P的一个原根,归根到底就是g^(P-1) = 1 (mod P)当且仅当指数为P-1的时候成立.(这里P是素数).
简单来说,g^i mod p ≠ g^j mod p (p为素数)
其中i≠j且i, j介於1至(p-1)之间
则g为p的原根。
m有原根的充要条件是 m= 1,2,4, p,2 p, p^n,其中 p是奇质数, n是任意 正整数。)
对正整数( a, m) = 1,如果 a 是模 m 的原根,那么 a 是 整数模n乘法群(即加法群 Z/m Z的可逆元,也就是所有与 m 互素的正整数构成的 等价类构成的乘法群) Zn的一个 生成元。由于 Zn有 φ( m)个元素,而它的生成元的个数就是它的可逆元个数,即 φ(φ( m))个,因此当模 m有原根时,它有φ(φ( m))个原根。

回归这题实际就是求φ(φ( P))=φ(P-1)。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;

int euler(int n)
{
    int res=n;
    for(int i=2;i*i<=n;i++)
    {
        if(n%i==0)
            res=res/i*(i-1);
        while(n%i==0)
            n/=i;
    }
    if(n>1)
        res=res/n*(n-1);
    return res;
}

int main()
{
    int n;
    while(cin>>n)
    {
        cout<<euler(n-1)<<endl;
    }
return 0;
}

POJ 2773 给定一个M,求第K个与M互素的数是多少

思路:先求出不大于M,且与M互素的数,并记录有多少个(即PHI(M)个),然后对于大于M时,不难发现在KM--(K+1)M的范围中,都有PHI(M)个数与M互素(自己列表写一写),也即第K个与M互素的数对M取余具有周期性且T=PHI(M),因此当求出了不大于M的PHI(M)个与M互素的数,剩下的可以用周期性求出比M大且与M互素的数。当然这是暴力的做法,网上用容斥定理+二分可以完美解决,虽然不明觉厉。。。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=100000005;
int prime[maxn];

int gcd(int a,int b)
{
    if(b==0)
        return a;
    else
        return gcd(b,a%b);
}
int main()
{
    int m,k;
    while(cin>>m>>k)
    {
        int cnt=0;
        for(int i=1;i<=m;i++)
        {
            if(gcd(m,i)==1)
                prime[cnt++]=i;
        }
        if(k%cnt!=0)
            cout<<(k/cnt)*m+prime[k%cnt-1]<<endl;
        else
        cout<<(k/cnt-1)*m+prime[cnt-1]<<endl;
    }
    return 0;
}

POJ 2478 给定一个N,快速求PHI(1)+PHI(2)+.....PHI(N)的和。

如果用前面那种一个一个求PHI的模板,直接TLE,因此得打表生成PHI(N)的数组,打表的思路与筛法类似,记住就好。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int n;
int phi[1000005];
void euler()
{
    for(int i=1;i<=1000000;i++)
        phi[i]=i;
    for(int i=2;i<=1000000;i+=2)
        phi[i]=phi[i]/2;
    for(int i=3;i<=1000000;i+=2)
    {
        if(phi[i]==i)
        {
            for(int j=i;j<=1000000;j+=i)
            {
                phi[j]=phi[j]/i*(i-1);
            }
        }
    }

}

int main()
{
    euler();
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0)
            return 0;
        long long  sum=0;
        for(int i=2;i<=n;i++)
        {
            sum+=phi[i];
        }
        printf("%I64d\n",sum);


    }
    return 0;
}

POJ 3090 求第一象限中从原点出发到各个格点组成的不同斜率的个数。

裸的法雷级数的知识:每一行从0/1开始,以1/1结尾,其它数自左至右将所有的真分数按增加顺序排列;第n行是由所有分母小于或等于n的真分数组成,我们称为n阶法雷级数。这里就是要求N阶法雷级数有多少个。

设法雷级数N阶有PHI(N)个,则不难得出PHI(N)=PHI(N-1)+phi(N):实际上就是在前一项的基础上多了分母为N,分子不大于N且与N互素的个数。

故PHI(N)=PHI(N-1)+phi(n)=PHI(N-2)+phi(N-1)+phi(N)----------->=sigema(phi(i))(i从1-n)+1。

回归这道题:第一象限不同斜率的个数:以斜率为1的射线为对称轴,射线下方符合条件的总数恰为sigema(phi(i))(i从1-n),上方亦如此,最后再加上对称轴上的一个点即为该题的解。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int phi[10005];

void euler()
{
    for(int i=1;i<=1000;i++)
        phi[i]=i;
    for(int i=2;i<=1000;i+=2)
        phi[i]/=2;
    for(int i=3;i<=1000;i+=2)
    {
        if(phi[i]==i)
        {
            for(int j=i;j<=1000;j+=i)
            {
                phi[j]=phi[j]/i*(i-1);
            }
        }
    }
}

int main()
{
    int t;
    cin>>t;
    int cas=0;
    euler();
    while(t--)
    {
        int n;
        cin>>n;
        int sum=0;
        for(int i=1;i<=n;i++)
            sum+=phi[i];
        cout<<++cas<<" "<<n<<" "<<2*sum+1<<endl;
    }
    return 0;
}
POJ 3358

Period of an Infinite Binary Expansion
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 2975 Accepted: 787

Description

Let {x} = 0.a1a2a3... be the binary representation of the fractional part of a rational number z. Suppose that {x} is periodic then, we can write

{x} = 0.a1a2...ar(ar+1ar+2...ar+s)w

for some integers r and s with r ≥ 0 and s > 0. Also, (ar+1ar+2...ar+s)wdenotes a nonterminating and repeating binary subsequence of {x}.

The subsequence x1 = a1a2 ... aris called the preperiod of {x} and x2 = ar+1ar+2 ... ar+s is the period of {x}.

Suppose that |x1| and |x2| are chosen as small as possible then x1 is called the least preperiod and x2 is called the least period of {x}.

For example, x = 1/10 = 0.0001100110011(00110011)w and 0001100110011 is a preperiod and 00110011 is a period of 1/10.

However, we can write 1/10 also as 1/10 = 0.0(0011)w and 0 is the least preperiod and 0011 is the least period of 1/10.

The least period of 1/10 starts at the 2nd bit to the right of the binary point and the the length of the least period is 4.

Write a program that finds the position of the first bit of the least period and the length of the least period where the preperiod is also the minimum of a positive rational number less than 1.

Input

Each line is test case. It represents a rational number p/q where p and q are integers, p ≥ 0 and q > 0.

Output

Each line corresponds to a single test case. It represents a pair where the first number is the position of the first bit of the least period and the the second number is the length of the least period of the rational number.

Sample Input

1/10 
1/5 
101/120 
121/1472

Sample Output

Case #1: 2,4 
Case #2: 1,4 
Case #3: 4,4 
Case #4: 7,11
题意:求一个分数n/m在二进制形式表示下的最小循环节长度以及起点位置。

思路:

现在假设起始循环的第i个数为n,记作ni ;那么第j个数n,则是nj;这时循环数列出现,那么循环数列的长度为 L = j - i .

又根据小数点进制的计算原理,那么就有nj = ( ni * 2 ^ L ) % m ;————>2 ^ L % m == 1 % m ;(求t是利用这里求的)

 当 m  与 2 互质时,根据欧拉定理,则有2^ phi( m ) == 1 %m ,因为2^ 0 == 1 , 所以起始点为0 ;也就是题目的1;

当二者不互质时,那么m % 2 != 0 ;

因此对等式进行化简 ,两边同时除以2的幂次(使得m与2互质,直到满足欧拉函数的条件),那么就有2^( L - t ) == 1 % ( m / ( 2 ^ t );可知,此时循环数列的起点为 t ,也就是题目的t+1;

最后我们要求的就是2^ L' = 1 % M' ;由于2^ k == 1 % m ',当k % m == 0 时取得有效值,因此,从小到大枚举phi(m')的因子,可得到最大值

这题是很好的一题,思路是别人的,今天跟世权做这题的时候已经再往这方面想了,但是当时打表暴力找的时候只是猜到了最小循环节会是phi()的一个因子,但是没有想到如何求起点,后来看了一下别人的思路,便也明白了如何来求起点。


#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int fac[1000005];
int phi;
int temp;
int p,q;
int euler(int n)
{
    int res=n;
    for(int  i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            res=res/i*(i-1);
            while(n%i==0)
                n/=i;
        }
    }
    if(n>1)
        res=res/n*(n-1);
    return res;
}
int gcd(int a,int b)
{
    if(b==0)return a;
    else
        return gcd(b,a%b);
}
int power(int a,int b,int mod)
{
    int ans=1;
    while(b)
    {
        if(b&1)
            ans=(long long )ans*a%mod;
        b>>=1;
        a=(long long )a*a%mod;
    }
    return ans;
}

int main()
{


    int cas=0;
    while(scanf("%d/%d",&p,&q)!=EOF)
    {
        int g=gcd(p,q);
        p/=g;
        q/=g;
       int  len=0;
       while(q%2==0)
       {
           len++;
           q/=2;
       }
       int  ans1=len+1;
       int  ans2;
       phi=euler(q);
       if(phi==1)
       {
           ans2=1;
       }
       else
       {
           int  cnt=0;
           for(int  i=1;i*i<=phi;i++)
           {
               if(phi%i==0)
               {
                   fac[cnt++]=i;
                   fac[cnt++]=phi/i;
               }
           }
           sort(fac,fac+cnt);
           for(int i=0;i<cnt;i++)
           {
               temp=power(2,fac[i],q);
               if(temp==1)
               {
                   ans2=fac[i];
                   break;
               }
           }

       }
       printf( "Case #%d: %d,%d\n" , ++cas , ans1 , ans2 ) ;
    }
            return 0;

}


欧拉函数是数论中很基础的东西,这方面的比较专业性的证明,我会在学弟写好他的长篇大论后将链接挂在这里,原来数学渣不会严谨的证明,只会乱猜= =|||




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值