1、tomnenu_OTZ,数论,求素数方法,怎么判断一个数是否为素数? bool IsPrime(unsigned n) for (unsigned i=2;in;+i) /和比它小的所有的数相除,如果都除不尽,证明素数 if (n%i=0)/除尽了,则是合数 return false; return true;笨蛋的作法:一个数去除以比它的一半还要大的数,一定除不尽,所以还用判断吗?,下面是中学生的做法:,bool IsPrime(unsigned n) for(unsigned i=2;i30000000000,数量级相当大。在一般的机子它不是一秒钟跑不出结果,它是好几分钟都跑不出结果 -_
2、-!,想锻炼耐心的同学不妨试一试在程序设计竞赛中就必须要设计出一种更好的算法要求能在几秒钟甚至一秒钟之内找出n以内的所有素数。于是就有了素数筛法。,筛法求素数,void Prime(int max) memset(flag, true, sizeof(flag); for(int i = 2; i = max / 2; i+) if(flagi) for(int j = i 1 ; j = max; j += i) flagj = false; for(int i = 2 ; i 1) / 一直计算到指数小于或等于1 if ( p / 最后把主体和“剩下的”乘起来作为结果,改进乘方算法应用于f
3、ibonacci,普通的算法求Fn的时间复杂度为O(n),当然如果要求求出所有的Fn,这种已经是最优的了,但是如果只求某一个Fn,可以改进,蒙格马利快速幂模算法,后面我们会用到这样一种运算:(XY)%Z问题是当X和Y很大时,只有32位的整型变量如何能够有效的计算出结果?考虑上面那份最终的优化代码和再上面提到过的积模分解公式,我想你也许会猛拍一下脑门,吸口气说:“哦,我懂了!”。,蒙格马利快速幂模算法,下面的讲解是给尚没有做出这样动作的同学们准备的。XY可以看作Y个X相乘,即然有积模分解公式,那么我们就可以把Y个X相乘再取模的过程分解开来,比如:(1725)%29则可分解为:( ( 17 * 1
4、7 ) % 29 * ( 17 * 17 ) % 29 * 如果用上面的代码将这个过程优化,那么我们就得到了著名的“蒙格马利”快速幂模算法:,unsigned Montgomery(unsigned n, unsigned p, unsigned m) / 快速计算 (n e) % m 的值,与power算法极类似 unsigned r = n % m; / 这里的r可不能省 unsigned k = 1; while (p 1) if (p / 还是同上,上面的代码还可以优化。下面是蒙格马利极速版:unsigned Montgomery(unsigned n,unsigned p,unsig
5、ned m) /快速计算(ne)%m的值 unsignedk=1; n%=m; while(p!=1) if(0!=(p,GCD(Great Common Divisor),定理:gcd(a,b) = gcd(b,a mod b) Euclid 算法int gcd ( int a, int b ) int mod;while ( mod = a % b ) a = b, b = mod;return b;/注意这里面必须a,b都为正数,否则要加其他判断语句,LCM(Least Common Multiple),有了 GCD, LCM 就好办了LCM ( a, b ) = a * b / GCD
6、 ( a, b ) 实际上最好写成a/GCD(a,b)*b思考:为什么下面的写法好?,扩展欧几里得算法,同时求出 v, u 使gcd ( a, b ) = u * a + v * b(重要)非递归的不好写,建议写递归的,扩展欧几里得算法,注意到对于gcd(a,b) = d 我们对(a, b)用欧几里德辗转相除会最终得到(d, 0)此时对于把a =d, b = 0 带入a*x + b*y = d,显然x = 1,y可以为任意值,这里y可以为任意值就意味着解会有无数个。我们可以用a = d, b = 0的情况逆推出来任何gcd(a, b) = d 满足a*x + b*y = d的解。如果x0, y
7、0是b*x + (a%b)*y = d 的解,那么对于a*x + b*y = d的解呢?,扩展欧几里得算法,b*x0 + (a%b)*y0 =d =b*x 0+ (a - a/b*b)*y0 =d = a*y 0+ b*(x0 - a/b*y0)=d,所以a*x + b*y = d的解x1 = y0, y1 = x0 - a/b*y0; 这样我们可以程序迭代了。,注:a,b为正整数,设集合A = x*a+y*b|x,y是整数,则A中最小正元素是gcd(a,b),扩展欧几里得算法,int exGcd(int a, int b, int ,其他一些关于约数的公式,若n=p1e1p2e2prer,则
8、 n的因数个数为 (1+e1)*(1+e2)*(1+er) n所有因数的和为(1+p1+p12+p1e1)*(1+p2+p22+p2e2) *(1+pr+pr2+prer),欧拉函数,(x)表示与x互质且小于x的正整数的个数如果x为素数,则欧拉函数等于x-1例如(8)=4,因为1,3,5,7均和8互质。 若n是质数p的k次幂,(n)=pk-p(k-1)=(p-1)p(k-1),因为除了p的倍数外,其他数都跟n互质。欧拉函数是积性函数若m,n互质,(mn)=(m)(n)。,欧拉函数,求法:将x分解为p1n1*p2n2*pknk,则欧拉函数=p1(n1-1)*pk(nk-1) *(p1-1)*(p
9、k-1),欧拉函数,欧拉函数的编程实现 利用欧拉函数和它本身不同质因数的关系,用筛法计算出某个范围内所有数的欧拉函数值。 欧拉函数和它本身不同质因数的关系: ()(/)(/); ()(/)(/)(/); ()(/),欧拉函数,int euler(int n) int i, j, k; int res = n; for(i = 0; pi 1) res = res / n * (n-1); return res;,.x的二进制长度,语法:result=BitLength(int x); 参数:x:测长的x返回值:x的二进制长度源程序:int BitLength(int x) int d = 0;
10、 while (x 0) x = 1; d+; return d;,返回x的二进制表示中从低到高的第i位,2.语法:result=BitAt(int x, int i); 参数: x:十进制 xi:要求二进制的第i位返回值:返回x的二进制表示中从低到高的第i位注意:最低位为第一位源程序:int BitAt(int x, int i) return ( x ,Exercise,欧拉函数:pku2478 pku2480 pku2407 pku1284快速幂模pku3070 http:/ 3233(选作)pku1845筛选法PKU 2262、2909、2739,1142欧几里得算法pku2115 1061,