ACM数论中的常见的模板和结论
1:最大公约数的求法
欧几里得算法实现。递归实现
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #include<iostream> 5 using namespace std; 6 __int64 gcd(__int64 y,__int64 x) 7 { 8 __int64 ans=0; 9 if(x==0) 10 ans=y; 11 else 12 ans=gcd(x,y%x); 13 return ans; 14 } 15 int main() 16 { 17 int t; 18 __int64 A,B; 19 scanf("%d",&t); 20 scanf("%I64d %I64d",&A,&B); 21 if(A>B) 22 swap(A,B); 23 printf("%I64d\n",gcd(A,B)); 24 } 25 return 0; 26 }
2:最小公倍数和最大公约数的关系
设n和m的最大公约数是p,最小公倍数是q,那么有下列的关系
p*q=n*m,所以求两数的最大公约数可以转换成求求两数的最大公约数再根据两者之间的关系来求最小公倍数= =
3:素数的判定
1> 试商法
int is_prime() { for(int i=2;i*i<=n;i++) { if(n%i==0) return 0; } return 1; }
2>筛选法
数组a[]存的是1000000以内的素数
int get_prme() { int k=0; for(int i=2;i<=1000000;i++) { if(!chick[i]) a[k++]=i; for(int j=0;j<k;j++) { if(i*a[j]>1000000) break; chick[a[j]*i]=1; if(i%a[j]==0) break; } } return 0; } //筛选法求素数
3:分解一个数的质因子,其中a[]存的是素数,f[]存的是某个数的质因子= =
int get_fx(int x) { int j,k=0; for( j=0;a[j]*a[j]<=x;j++) { if(x%a[j]==0) f[ k++]=a[j]; while(x%a[j]==0) { x=x/a[j]; f[k++]=a[j]; } if(x==1) break; } if(x!=1) f[k++]=x; return 0 }
4:能被11整除的数他满足(SUM奇-SUM偶)的绝对值能被11整除= =
5:快速幂算法
1 int qPow(int A, int n) 2 { 3 if (n == 0) return 1; 4 int rslt = 1; 5 6 while (n) 7 { 8 if (n & 1) //如果n为奇数 9 { 10 rslt *= A%10; 11 } 12 A *= A; 13 n >>= 1; 14 } 15 return rslt%10; 16 }
运用快速幂算法可以把求n^n的复杂度讲到logn,
6:求n^n的个位数
因为是各位数没有进位,通过打表发现n的各位数是0,1,2,5,6,7的话无论是多少次幂他的个位数都是他自己本身= =
然后我们看其他的
2:4 6 8 2
3:3 9 7 1
4:6 4 6 1
8:4 2 6 8
9:1 9 1 9
上面的数阵表示当n的个位数是2,3,4,8,9是n次幂之后的结果变化,然后因为只有四个数的变化我们考虑n%4,而且n%4的结果只会是0,2...
所以综上所述我们可以得出下面的数组
1 int data[10][4]={{0,0,0,0},{1,1,1,1},{6,6,4,4},{3,3,7,7},{6,4,6,4},{5,5,5,5,},{6,6,6,6},{7,7,3,3},{6,6,4,4},{1,9,1,9}};
下面给出完整代码
#include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> using namespace std; int data[10][4]={{0,0,0,0},{1,1,1,1},{6,6,4,4},{3,3,7,7},{6,4,6,4},{5,5,5,5,},{6,6,6,6},{7,7,3,3},{6,6,4,4},{1,9,1,9}}; int main() { int n; while(scanf("%d",&n)!=EOF) printf("%d\n",data[n%10][n%4]); return 0; }
参考博客http://m.blog.csdn.net/blog/chenminghe271/6766472
7:n的阶乘后面的零
通过打表可以得出结论n的阶乘后面的零呈现下面的规律
0 0,1 0,2 0,3 0,4 0,5 1,6 1,7 1,8 1,9 1,10 2,11 2,13 2,14 2,15 3,16 3,17 3,18 3,19 3,20 4;ps(11 2表示11的阶乘后面有2个0)每五个数0的数就会+1
我们进行25的打表的是发现25!后面有6个0,而24的阶乘后面只有4个零。这里发生突变了,不是平常的+1,而是+2。而且有关5的次方幂的数都会发生突变,。
那个突变的规律就是1+n(n表示m这个数可以用5^m来表示。。。
#include<stdio.h> #include<string.h> #include<algorithm> #include<iostream> #include<stack> #include<set> #include<queue> #include<math.h> #define maxn 100000 #define long long LL using namespace std; int main() { int n; scanf("%d",&n); int sum=0; int i=1; int ans=0; while(sum<n) { ans+=n/pow(5,i); sum=pow(5,i); i++; } printf("%d\n",ans); return 0; }
8:快速幂取余
快速幂取余其实就是在求快速幂的时候每一步都取余
#include<stdio.h> #include<string.h> #include<algorithm> #include<iostream> using namespace std; int qpow(int x,int a,int p) { int ans=1; x=x%p; while(a>0) { if(a&1) ans=(ans*x)%p; x=(x*x)%p; a>>=1; } return ans; } int main() { int A,B,C; scanf("%d %d %d",&A,&B,&C); printf("%d\n",qpow(A,B,C)); return 0; }//求A^B%C