日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

The Last Non-zero Digit POJ - 1150(n!mod p)

發布時間:2023/12/4 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 The Last Non-zero Digit POJ - 1150(n!mod p) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題意:

要求你求出n!(n?m)!)\frac{n!}{(n-m)!)}(n?m)!)n!?中最后一個非0的數字.

題目:

In this problem you will be given two decimal integer numberN,M. You will have to find the last non-zero digit of the NPM^{N}P_{M}NPM?.This means no of permutations of N things taking M at a time.

Input

The input contains several lines of input. Each line of the input file contains two integers N (0 <= N<= 20000000), M (0 <= M <= N).

Output

For each line of the input you should output a single digit, which is the last non-zero digit of NPM. For example, if NPM^{N}P_{M}NPM? is 720 then the last non-zero digit is 2. So in this case your output should be 2.

Sample Input

10 10
10 5
25 6

Sample Output

8
4
2

分析:

說實話這道題上來我就沒看懂題意,這怎么就NPM^{N}P_{M}NPM?==n!(n?m)!)\frac{n!}{(n-m)!)}(n?m)!)n!?了?In a word ,我感覺到了不友好。
然后我就開始了啃書環節,具體在《挑戰程序設計》P293,之后惡意鋪面而來,花費我一晚上,終于摸透了這個題,必須滴好好說道說道。
(1)首先是若求n!的最后一位,我們可以將所有的因數10去掉,問題就轉換為了求這個數的最后一位。根據以往的做題經驗,這時候只要找到所有的因子2和5,放著對最后特判對于最后一位的影響就好了,所以正常while循環暴力找因子數,然后超時了,代碼如下:

#include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; typedef long long ll;const int N=2e7+10; int a[5][N]; int b[5][4]={{6,2,4,8},{5,5,5,5},{1,3,9,7},{1,7,9,3},{1,9,1,9}}; int get(int x){if(x==2) return 0;if(x==5) return 1;if(x==3) return 2;if(x==7) return 3;if(x==9) return 4; } void init(){for(int i=2; i<N; ++i){int t=i;int su=0,sm=0;while(t%2==0) t/=2,++su;while(t%5==0) t/=5,++sm;a[get(2)][i]=a[get(2)][i-1]+su;a[get(5)][i]=a[get(5)][i-1]+sm;a[get(3)][i]=a[get(3)][i-1];a[get(7)][i]=a[get(7)][i-1];a[get(9)][i]=a[get(9)][i-1];if(t%10 && t%10!=1) ++a[get(t%10)][i];} }int main() {init();int n,m;while(~scanf("%d%d",&n,&m)){int su=a[get(2)][n]-a[get(2)][n-m];int sm=a[get(5)][n]-a[get(5)][n-m];if(su<sm) printf("5\n");else {//printf("+++++++ %d %d\n",su,sm);su-=sm;int d3=a[get(3)][n]-a[get(3)][n-m];int d7=a[get(7)][n]-a[get(7)][n-m];int d9=a[get(9)][n]-a[get(9)][n-m];int tmp=b[get(3)][d3%4]*b[get(7)][d7%4]*b[get(9)][d9%4];//printf("+++++++++ %d %d\n",su,tmp);tmp*=su?b[get(2)][su%4]:1;int ans=tmp%10;printf("%d\n",ans);}}return 0; }

這并不冤枉,其實開數組2e7就該知道有問題,試了編譯器,可以運行,就硬著頭皮寫下來了,不出意料,果真超時了。那這里就用到了“白書”的定理,我懶得敲了。

具體代碼如下:

int sum(int n,int p){//計算n!中質因子m的出現次數return n==0?0:n/p+sum(n/p,p); }

(2)當我們對(1~n)去除因子2,5后發現最后一位的值,只可能是 1,3, 7,9這四個數,因為最后一位若為1,n!相乘對最后一位值的變化沒有影響,所以可以不用考慮,只考慮 3,7 ,9,即可。這時發現了規律,例如,即當存在多個3時,只考慮個位值,出現了循環節{1,3,9,7},注意第一位為整除時,所以為值為1。你以為到這就算完了,還不夠!

(3)如上超時代碼,不能打表開數組存,所以每次輸入就直接調用函數,直接對n!進行討論,將其分為奇偶兩個部分:
【1】對于偶數序列,我們只需將它除 2 即可遞歸轉化為奇數序列(其實就是消去因子2)。
【2】對于奇數序列,我們可以發現,每 10個數字中就有 3 , 7 , 9 各一個,但又因為(1~n)中有 5的倍數,所以繼續除 5,遞歸消去因子。
(4)這里就差不多了,但還是要注意:
一,當因子2的個數小于5的個數時,由于此時末尾必為奇數(1,3,7,9中一個),所以相乘最后一位必為5,直接輸出。
二,當因子2的個數大于5的個數時,需要考慮因子2對結果的一個影響,這時也有與前面一樣的規律{6,2,4,8},理解了之后讓我們歡樂敲代碼吧;

AC模板:

#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; int n,m; int e[4][4]={{6,2,4,8},{1,3,9,7},{1,7,9,3},{1,9,1,9}}; int sum(int n,int p){//計算n!中質因子m的出現次數,用到“挑戰程序設計”P293推論return n==0?0:n/p+sum(n/p,p); } int odd(int n,int p){//奇數數列中末尾為x的數出現的次數,消去1~n數中存在的因子5return n==0?0:n/10+(n%10>=p)+odd(n/5,p); } int even(int n,int p){//末尾為x的數的出現次數,消去1~n數中存在的因子2;return n==0?0:even(n/2,p)+odd(n,p); } int main() {while(~scanf("%d%d",&n,&m)){int su=sum(n,2)-sum(n-m,2);int sm=sum(n,5)-sum(n-m,5);int a=even(n,3)-even(n-m,3);int b=even(n,7)-even(n-m,7);int c=even(n,9)-even(n-m,9);if(su<sm){printf("5\n");continue;}int ans=e[1][a%4]*e[2][b%4]*e[3][c%4]%10;if(su!=sm)ans*=e[0][(su-sm)%4];printf("%d\n",ans%10);}return 0; }

備戰ccpc分站賽ing ,題目分析簡略,見諒,轉載請注明出處。。。。。

總結

以上是生活随笔為你收集整理的The Last Non-zero Digit POJ - 1150(n!mod p)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。