POJ 1150-The Last Non-zero Digit

来源:互联网 发布:淘宝网代理一件代发 编辑:程序博客网 时间:2024/05/18 04:01

题意:

求排列数n,m的最后一个非零数字。


下面是超时程序:

#include<iostream>#include<cstring>#include<string>#include<algorithm>#include<cstdio>#include<cmath>using namespace std;int fun(int a, int b, int c) //a的b次方对c取模{if(b == 0) return 1;if(b == 1) return a % c;long long tmp = fun(a, b / 2, c);return (((tmp * tmp % c) * (b & 1 ? a : 1)) % c) % c;}int get2(int n) //n的阶乘中2的个数{int count = 0;while(n /= 2)count += n;return count;}int get5(int n) //n的阶乘中5的个数{int count = 0;while(n /= 5)count += n;return count;}int main(){//freopen("Input.txt", "r", stdin);int n, m, sum2, sum5, res, sum;while(scanf("%d%d", &n, &m) != EOF){sum2 = get2(n) - get2(n - m);sum5 = get5(n) - get5(n - m);res = (sum2 >= sum5 ? sum2 - sum5 : sum5 - sum2); //2的个数和5的个数的差值sum = 1;for(int i = n; i >= n - m + 1; --i){sum *= i;while(sum % 2 == 0) sum /= 2;while(sum % 5 == 0) sum /= 5;sum %= 10;}if(sum2 >= sum5) //加上2或5对结果的影响sum *= fun(2, res, 10);elsesum *= fun(5, res, 10);printf("%d\n", sum % 10);}return 0;}

看过之后才明白有规律,优化后代码:

/*如何求出n!阶乘最后非0位?比如说我们要找10!最后非0位,由于质因数2和5组合之后会使得末尾产生0.那么我们不妨把10!中2,5质因数全部去掉,(但是请注意2的数目其实比5的要多,所以我们要在最后考虑多余的2对末位的影响)如 1*2*3*4*5*6*7*8*9*10 去掉2 ,5 因子后 就是1*1*3*1*1*3*7*1*9*1,由于2,5因子已经被去除,那么剩下的数字末尾一定是3,7,9,1中四者之一。然后我们再求出这么一串数相乘以后末尾的数是几.最后再补上2对末位的影响即可!总结一下,求10!最后一个非0位的步骤如下:step1:首先将10!中所有2,5因子去掉;step2:然后求出剩下的一串数字相乘后末尾的那个数。step3:由于去掉的2比5多,最后还要考虑多余的那部分2对结果的影响。step4:output your answer!正如上面文章里所说的“To compute the number of 3,7,9 among (f(1) mod 10), (f(2) mod 10), ..., (f(N) mod 10) is not so easy”,这里面步骤2是个难点。如何求出剩下的这串数字相乘后最后一位是几呢?这可以转化成求出这些数里面末尾是3,7,9的数字出现的次数(为啥?因为这些数的n次方是有规律的,周期为4,不信你可以推一下)好,现在问题就是如何求出这串数字中末尾3,7,9各自出现的次数了;一个数列实际上可以分成偶数列和奇数列,以1*2*3*4*5*6*7*8*9*10为例分成1 3 5 7 9,   2 4 6 8 10这样我们尝试分别进行统计,可以发现,实际上2,4,6,8,10中的个数也就是1 2 3 4 5中的个数,也就是说我们又把这个问题划分成了一个原来问题的子问题。f(n) = f(n/2) + g(n),g(n)表示奇数列中的数目,所以我们需要解决g(n)再次观察g(n)实际上又分成了两部分1 3 7 9 11 13 17 19 21。。。以及5的奇倍数5,15,25。。。说明又出现了子问题,如果要统计这个数列中末尾为x(1,3,7,9)的个数可以这样写:g(n,x) = n/10+(n%10 >= x)+g(n/5,x)  这样利用了两个递归方程,我们就可以在lgn的时间内计算出末尾为1,3,7,9的数的个数了好了,现在我们得到了这串数字中末尾是3,7,9的数字的个数,我们利用循环节的性质可以快速地算出这串数字相乘后mod 10的结果,在考虑下当时多除的2(其实也可以用循环节来处理),便可求出答案!解决了上面两个子问题,我想求P(n,m)最后一个非0位就变得十分容易了。P(n,m)实际上等于 n! / (n-m)!我们可以求出n! 和(n-m)!中质因数2,5,3,7,9分别出现的次数,然后再各自相减。然后再用循环节处理,即可!BTW,这里还要注意一个trick,就是2的出现次数如果小于5,(这对于排列数来说是可能的)我们可以直接输出5,如果2的数目等于5,那么2的循环节不需要考虑。至于3,7,9的循环节,由于这些数的4次方末位刚好是1,所以就不需要特殊考虑了。*/#include<cstdio>int getx(int n,int x){    if(n==0)  return 0;    return n/x+getx(n/x,x);}int g(int n,int x){    if(n==0)  return 0;    return n/10+(n%10>=x)+g(n/5,x);}int get(int n,int x){    if(n==0)  return 0;    return get(n/2,x)+g(n,x);}int table[4][4] ={    6,2,4,8,//2    ^n%10的循环节,注意如果2的个数为0时候,结果应该是1,要特殊处理。    1,3,9,7,//3    1,7,9,3,//7    1,9,1,9,//9};//3,7,9的循环节中第一位,刚好是1,故不需要考虑这些数字出现次数为0的情况。int main(){    int n,m;    int num2,num3,num5,num7,num9;    while(scanf("%d%d",&n,&m)!=EOF)//n!/(n-m)!的右边第一个非0位    {        num2=getx(n,2)-getx(n-m,2);        num3=get(n,3)-get(n-m,3);        num5=getx(n,5)-getx(n-m,5);        num7=get(n,7)-get(n-m,7);        num9=get(n,9)-get(n-m,9);        int res=1;        if(num5>num2)        {            printf("5/n");            continue;        }        else        {            if(num2!=num5)            {                res*=table[0][(num2-num5)%4];                res=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\n",res);    }    return 0;}


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 nba篮球大师身体素质满了怎么办 钉鞋大了一码怎么办 篮球鞋鞋垫会向里面跑怎么办 穿高跟鞋脚肿了怎么办 衣服弄到单车油怎么办 高低床孩子摔下来怎么办 量血压时老紧张怎么办 牛仔外套的扣子掉了怎么办 裤子的裤筒大了怎么办 衣服拉链驰坏了怎么办 小脚裤裤腿紧了怎么办 地垫粘地板了怎么办 棉麻衬衣皱了怎么办 麻料衣服烫皱了怎么办 在京东买一双奥康鞋没有防伪怎么办 足球鞋丁掉了一颗怎么办 鼻子有点大想变小该怎么办 阿勒泰小东沟风景区边防证怎么办 孩子上一年级了学习很差怎么办 孩子作息时间不规律怎么办 冬天冻脸怎么办小妙招 冬天冻脚怎么办小妙招 冬天脚冷怎么办小妙招 初中生不爱学习父母该怎么办 早孕办公室买新办公桌怎么办 一年级学生专注度差怎么办 pscs6界面字体太小怎么办 psd文件打不开程序错误怎么办 经常熬夜皮肤暗黄怎么办 炎症引起的经期不来怎么办 父母沉迷于炒股该怎么办 宝宝嘴周边红了怎么办 后背被嘴吸出牙印怎么办 宝宝嘴巴周围长湿疹怎么办 宝宝脸蛋都是红红的湿疹怎么办 药流药第一天晚上的忘吃怎么办 我有口臭不想出门怎么办 入职10天想辞职怎么办 提完辞职报告不想上班了怎么办 吃流产药出血少怎么办 新车漆被刮掉了怎么办