• #数论-模运算#POJ 1150、1284、2115


    1.POJ 1150 The Last Non-zero Digit #质因数分解+模运算分治#

    先贴两份题解:

    http://www.hankcs.com/program/algorithm/poj-1150-the-last-non-zero-digit.html

    http://www.cppblog.com/abilitytao/archive/2009/10/31/99907.html

    下面是自己看完题解(划掉)之后的理解:

    题目要求出组合数Anm=n!/(n-m)!(说实话一开始不知道题目中的NPM到底什么意思。。)的最后一个非零位,那么可以来看看n!的最后一个非零位该如何求得。

    求n!:

    (1)首先,n!的所有10因子都是要去掉的(因为求非零位),那么2和5也要一对一对的去掉;

    (2)接下来把数列分成奇数列:1 2 3 4 5 6 7 8 9 10 –> 1 3 5 7 9 | 2 4 6 8 10

            故有f(n )=f(n/2 )+g(n );

            g(n )可以再分为:1 3 5 7 9 11 13 17 19 21 ……和5的奇数倍 5 15 25……

            故设这个数列中末尾为x(x=1,3,7,9)的个数 g(n,x )=n/10+(n%10>=x)+g(n/5,x );

    (3)最后再对数列中末尾为2和5的个数进行比较、特判一下即可。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    
    //计算n!中质因子(2/5)的出现次数
    int get_2_5(int n,int num)
    {
        if(n==0) return 0;
        return n/num+get_2_5(n/num,num);
    }
    
    //计算奇数数列中末尾为x的数的出现次数
    int g(int n,int x)
    {
        if(n==0) return 0;
        return n/10+(n%10>=x)+g(n/5,x);
        //数列还能再次分出子问题,故有g(n/5,x)
    }
    
    //计算数列中末尾为x的数的出现次数
    int getx(int n,int x)
    {
        if(n==0) return 0;
        return getx(n/2,x)+g(n,x);
    }
    
    int table[4][4]={
        6,2,4,8,//2^n%10的循环节
        1,3,9,7,//3
        1,7,9,3,//7
        1,9,1,9 //9
    };
    
    int main()
    {
        int n,m;
        while(~scanf("%d %d",&n,&m))
        {
            int num2=get_2_5(n,2)-get_2_5(n-m,2);
            int num5=get_2_5(n,5)-get_2_5(n-m,5);
            int num3=getx(n,3)-getx(n-m,3);
            int num7=getx(n,7)-getx(n-m,7);
            int num9=getx(n,9)-getx(n-m,9);
    
            int res=1;
            if(num2<num5)
            {
                printf("5
    ");
                continue;
            }
            else
            {
                if(num2!=num5)
                {//if num2==num5 那么res应该*1
                    res*=table[0][(num2-num5)%4];
                    res%=10;
                }
    
                res*=table[1][num3%4];
                res%=10;
                res*=table[2][num7%4];
                res%=10;
                res*=table[3][num9%4];
                res%=10;
            }
            printf("%d
    ",res);
        }
    }


    2.POJ 1284 Primitive Roots #欧拉函数#

    有一个关于原根的概念:若p有原根,则它恰有φ(φ( p))个不同的原根。

    欧拉函数定义:对于正整数p,<=p且与p互质的正整数(包括1)的个数记作φ( p)。

    这道题其实就是求欧拉数。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    
    int Euler(int n)
    {
        int res=n;
        for(int i=2;i*i<=n;i++)
        {
            while(n%i==0)
            {
                n/=i; res-=(res/i);
                while(n%i==0)
                    n/=i;
            }
        }
        if(n>1)
           res-=(res/n);
        return res;
    }
    
    int main()
    {
        int p;
        while(~scanf("%d",&p))
            printf("%d
    ",Euler(p-1));
        return 0;
    }


    3.POJ 2115 C Looooops #扩展欧几里得#
    http://blog.csdn.net/lyy289065406/article/details/6648546

    题意:

            对于C,for(i=A ; i!=B ;i +=C),在k位存储系统中循环几次才结束。

    若在有限次内结束,则输出循环次数n,否则输出FOREVER)

    分析推导就直接看大牛的了,代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<cstdlib>
    #include<vector>
    #include<stack>
    #include<map>
    using namespace std;
    typedef long long ll;
    
    ll extend_gcd(ll a,ll b,ll &x,ll &y)
    {  //return d=gcd(a,n);
        if(b==0)
        {
            x=1,y=0;
            return a;
        }
        else
        {
            ll t=extend_gcd(b,a%b,x,y);
            ll xx=x,yy=y;
            x=yy;
            y=xx-(a/b)*yy;
            return t;
        }
    }
    
    int main()
    {
        ll A,B,C,k,x,y;
        while(~scanf("%I64d %I64d %I64d %I64d",&A,&B,&C,&k))
        {
            if(A==0&&B==0&&C==0&&k==0)  break;
            ll a=C,b=B-A,n=(ll)1<<k; //n=2^k
            ll d=extend_gcd(a,n,x,y);
    
            if(b%d!=0) //方程无解
                printf("FOREVER
    ");
            else
            {
                x=(x*(b/d))%n;  //x为方程ax=b(mod n)的最小解
                x=(x%(n/d)+n/d)%(n/d);  //x为方程ax=b(mod n)的最小整数解
                printf("%I64d
    ",x);
            }
        }
        return 0;
    }
  • 相关阅读:
    软工实践寒假作业(2/2)
    软工实践寒假作业(1/2)
    个人作业——软件工程实践总结&个人技术博客
    个人技术总结——postman的接口请求
    个人作业——软件评测
    结对第二次作业——某次疫情统计可视化的实现
    结对第一次—疫情统计可视化(原型设计)
    软工实践寒假作业(2/2)
    软工实践寒假作业(1/2)
    个人作业——软件工程实践总结&个人技术博客
  • 原文地址:https://www.cnblogs.com/atmacmer/p/5532021.html
Copyright © 2020-2023  润新知