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,2aiai+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]+……
 
其中[]表示向下取整
 
 
posted @ 2012-04-20 13:25  龙杉老师  阅读(457)  评论(0编辑  收藏  举报