欧拉定理的应用

来源:互联网 发布:java 高性能 并发库 编辑:程序博客网 时间:2024/04/27 20:48
欧拉定理的应用
         定理1(Fermat):如果p是素数,则对任意的a,有ap-1 mod p = 1。
    定理2(Euler):如果p不是素数,则对任意的gcd(a, p)=1,有a(p)φ(p) mod p =1,其中
,p1,p2,……pk是p的所有素数因子。

【程序1】快乐2004
         考虑到一个正整数x,s是所有2004x的因子的和,你的目标是求出s除以29的余数。
    当x=1时,20041的所有因子为1,2,3,4,6,12,167,334,501,668,1002和2004,因此s=4704,而4704 mod 29=6。
输入:
    输入有多个测试序列,每个测试序列一行一个正整数x,(1<=x<=10 000 000)。
    x=0表示输入结束,并且不需要处理。
输出:
    对每个测试序列,输出一行就是s除以29的余数。
输入样例:
10000
0
输出样例:
10

【解题思路】
    题目要求的是2004x的因子和对29取模的结果。
    求某个数a的所有因子和,首先将该数分解:
    a = p1r1×p2r2×...×pnrn,其中p1, p2, ... ,pn都是素数,则a的任意因子可以表示为:
    d = p1i1×p2i2×...×pnin,其中0<=i1<=r1,...,0<= in<=rn
    将其求和,为
    例如,2004 = 22×3×167,则
        
    而2004x = 22x×3x×167x
    ,其中 r=(22x+1-1)(3x+1-1)(167x+1-1)。
    X还很大(1<=X<=10 000 000),根据Fermat定理,任意素数p,任意数a,有ap-1 mod p=1,则a28 mod 29=1,所以ab mod 29 = a(b mod 28) mod 29。
    所以首先将x对28取模,x=X mod 28是取模的结果,x就很小了(0<=x<28,有了这点,输入的X再大也没有关系),简单计算就可以得到r的值。
    最后,考虑到:s = (r mod 29)/332,即r+29k = 332S,k是满足等式的任意整数。
    而9×332-103×29=1,9×(r+29k) = 9×332S = S+103×29S
    所以r×9 mod 29 = S mod 29
    例如,当X=10 000时,计算200410000 = 210000×310000×16710000的所有因子和对29取模的结果,
    其
    20001 mod 28=9, 10001 mod 28=5, 167 mod 29=22
    r=(29-1)(35-1)(225-1) mod 29 = 18×10×12 mod 29 = 14。
    S mod 29 = r × 9 mod 29 = 14 × 9 mod 29 = 10, 200410000的所有因子和对29取模的结果是10。
int mod29(int x){    for(r=0; r<=x; ++r){f = f * (r==x?2:4) % 29;t = t * 3 % 29;    }    r = (f-1)*(t-1)*(d-1) % 29;    return r * 9 % 29;}int main(){    while(cin >> x) cout << mod29(x % 28));}

【程序2】2x mod n=1
        给定一个整数n,求一个最小的整数x,使得2x mod n=1
输入:
    每行一个正整数n(0<=n<=231-1)
输出:
    如果最小的正整数存在,输出一行2^x mod nl=1,其中的x和n用输入的n值和最小的x代替;否则,输出一行2^? mod n=1。
输入样例:
2
5
输出样例:
2^? mod 2=1
2^? mod 5=1

【解题思路】
    本题首先想到的可能是蛮力搜索,从x=1开始,逐步加大x,找到使得2^x mod n=1的x就输出。但考虑n比较大,满足2^x mod n=1的x可能也很大,所以直接求解的方法不行。
    根据Euler定理,当p是奇数时,aφ(p) mod p =1,而
    
    因此,2φ(n) mod n =1,φ(n)似乎就是答案。但题目要求的是满足2^x mod n=1最小的x,所以在某些情况下φ(n)≠x。例如,n=7,φ(n)=6,2^6 mod 7=1,但2^3 mod 7=1,最小的x是3。但可以推导出x一定是φ(n)的因子:如果x是满足2^x mod n=1最小的x,假设x不是φ(n)的因子,则r=φ(n) mod x, r大于0(因为假设x不是φ(n)的因子),同时r<x,注意到2φ(n) mod n=1,而且2x mod n=1,所以2r mod n=1,则存在一个比x还小的正整数,使得2r mod n=1,与假设x是最小矛盾。所以x一定是φ(n)的因子。
核心代码及注释:int prime[5000], n_prime; //根据素数分布定律,小于46340的素数约5000个sieve(){    short p[23170];    //求所有小于46340的素数,因为大于2的偶数都不是素数,所以筛法只对应所有的      大于1小于46340的奇数    //如果p[i]=1表示2*i+3素数,否则p[i]=0表示2*i+3不是素数    for(i=0; i<23170; ++i) p[i]=1; //初始化,假定所有奇数都是素数    for(i=0; i<106; ++i)if(p[i])  for(k=(i << 1)+3,j=(k+1)*(i+1)-1; j<23170; j+=k) p[j]=0;    for(prime[i=j=0]=2; i<23170; ++i)if (p[i]) prime[++j]=(i << 1)+3;    n_prime=j+1;}int ttn(int i, int n){  __int64 t=2,r=1; //用64位长整型防止中间结果溢出,t=22i,r=2i mod n  while(i){      if(i&l) r=t*r % n;      t=t*t % n;      i>>=1;  }  return r;}int phi(int n){  result=temp=n;  k=sqrt(n);  for(i=0; prime[i]<=k && i<n_prime; ++i)      if(!(temp % prime[i])){  //如果prime[i]是n的因子           do              temp/=prime[i];              while(!(temp % prime[i]));                  result = result/prime[i]*(prime[i]-1);              k=sqrt(temp);      }  if(temp-1) result = result/temp*(temp-1);  return result;}int main(){    sieve();    while(scanf("%d",&n)!=EOF){      if(n<2 || !(n&1)){        printf("2^? mod %d=1\n",n);        continue;      }     x=temp=phi(n);     for(i=j=0; prime[i]<=k && i<n_prime; ++i)  //列出phi(n)的所有素数因子        if(!(temp % prime[i])) r[j++]=prime[i]; //r记录phi(n)的所有素数因子     if(j==0 && temp>1) r[j++]=temp;     for(i=0; i<j; ++i){        while (x%r[i]==0 && (k=ttn(x,n)==1) x/=r[i];  //result是phi(p)的因子        if (k!=l) x*=r[i];     }     printf("2^%d mod %d=1\n",x,n);    }}



欧拉函数
        欧拉函数是指:对于一个正整数n,小于n且和n互质的正整数(包括1)的个数,记作φ(n) 。
    通式为:
    对于质数p,φ(p) = p - 1。注意φ(1)=1.
    特殊性质:当n为奇数时,φ(2n)=φ(n)

    欧拉函数是积性函数——若m,n互质,φ(mn)=φ(m)φ(n)。
    若n是质数p的k次幂,φ(n) = pk - pk-1 = (p-1)pk-1,因为除了p的倍数外,其他数都跟n互质。 
0 1