ACM数论小常识

—1 1)哥德巴赫猜想:
—一个大于等于4的偶数可以拆分为两个质数的和
(用10e6内的数据测试一下):
 
#include<iostream>

using namespace std; #include<conio.h>

#define M 1000000

int p[M]; bool is_prime(int n) { if(n<=1)return false; else 

    for(int i=2;i*i<=n;i++) if(n%i==0)return false; return true; } int main() { int n,i,j,k=0; for(i=2;i<=M;i++) if(is_prime(i))p[k++]=i; printf("%d ",k-1); while(1) { int q=1,s; cin>>n; if(n<4)printf("输入大于4的数"); else { for(i=0;i<=k-1;i++) { if(p[i]>=n)break; for(j=0;j<=k-1;j++) { s=p[i]+p[j]; if(p[j]>=n)break; if(s==n) { printf("YES\n%d %d\n",p[i],p[j]); q=0; break; } } if(!q)break; } } if(q)printf("NO\n不存在这两个数\n"); } return 0; }

 

—1判断组合数C(N,K)是否为奇数
—如果N&K==K则是奇数,反之则为偶数
测试代码如下:
#include<iostream>

using namespace std; int fun(int n,int k) { int s=1; for(int i=1;i<=k;i++) { s=s*(n--)/i; } return s; } int main() { int n,k; while(scanf("%d%d",&n,&k)!=EOF) { cout<<fun(n,k)<<endl; if((n&k)==k)printf("C(%d,%d)的阶乘为奇数\n",n,k); } return 0; }

 

—22N!末尾有多少个0:可以通过数N包含了多少个5,25,125…来计算
 
所谓零,就是5*2,所以 “n!末尾有多少个零”==“min(n!的质因子中5的数目,n!的质因子中2的数目”
又因为n!的质因子中5的数目必然小于等于2的数目,所以题目就变成了求n!的质因子中5的数目。
 
比如 26! 是 1*2*3*4*5*6……24*25*26,它们中间有多少个数能被5整除?当然是26/5=5个,但看25,它本身是5*5,也就是25代表着2个5,所以26!尾部零的数目等于 26/5 + 26/25 + 26/125 + ...
 
现在来计算1000!的末尾有多少个零,那么就是
1000/5 = 200
200/5 = 40 (写成1000/25也可以,但没这个意义了,下同)
40/5 = 8
8/5 = 1
结果就是 200+40+8+1 = 249
 
#include<iostream>

using namespace std; int main() { int n; while(scanf("%d",&n)!=EOF) { int s=0; while(n>=5) { n/=5; s+=n; } cout<<s<<"位0"<<endl; } return 0; }
 求素数方法
memset(vis,0,sizeof(vis)); m=sqrt(1000000); top=0; for(i=2;i<=m;i++) if(vis[i]==0){ prime[top++]=i; for(j=i*i;j<=n;j+=i) vis[j]=1; } for(i=m+1;i<1000000;i++) If(vis[i]==0) prime[top++]=i;

 

1)通常使用足够大的vis[N]数组来打一张表,若vis[p]==0,p为素数;
   vis[p]==1,p不是素数。
2)可以把素数都存在prime[]数组里,top是数组中素数的个数。
34~9行,以i=2为例,所有2的倍数vis[j]都设为1,好像筛选似的吧.其他数类似。
4)10~12行,求出(m+1~1000000内所有的素数。
如何计算a^n
1)计算a*a*a**a*a*a,需要计算n-1乘法,时间复杂度O(n)
2)考虑实例a^4,计算b=a*a,再算c=b*b,则c=a^4,但是只用了两次乘法,效率提高。比如a^9=a*(a^4)*(a^4),只需用4次乘法,一般的,a^n时间复杂度为O(logn)
二分法
数学的魅力:
幂运算满足结合律
n 为偶数: a^n=a^(n/2)*a^(n/2);
n 为奇数: a^n=a^(n/2)*a^(n/2)*a;
保存 a^(n/2), 很容易求出 a^n;
大数取模
(a*b)%m=(a%m*b%m )%m;
求( 2^100000000000000 %10000;
提示:二分法,速度惊人的快速幂!!!
 
(a+b)%m=(a%m+b%m)%m;
Sn 为斐波那契数列前 10000 项的和,
Sn%10000
求最大公约数
辗转相除法
int gcd(int a,int b)
{
     return b==0?a:gcd(b,a%b);
}
正约数的个数
已知 n=p1^a1*p2^a2 *pk^ak ( 也就是 n 的素数分解 ) ,求 n 的约数个数。
分析: n 的约数一定包含素因子中的某几项,对 n 的某个素因子 pi ,它在约数中的指数可以是 0,1,2 ai ai+1 种情况,根据乘法原理:
n 的约数个数 =
a1+1 *(a2+1)…*(ak+1)
欧拉函数
小于n且与n互素的正整数的个数
 
 
如果n为素数,则欧拉函数等于n-1
 
求法:将n分解为p1^n1*p2^n2*pk^nk,则
 
 
欧拉函数=n*(1-1/p1)*(1-1/p2)…*(1-1/pk);
 
 
n!
 
 
 
n!=p1^n1*p2^n2**pk^nk
 
勒让德定理:
 
ni=[n/pi]+[n/pi^2]+[n/pi^3]+……
 
其中[]表示向下取整
 
 

你可能感兴趣的:(ACM)