POJ 1150 The Last Non-zero Digit 数论+容斥
POJ 1150 The Last Non-zero Digit 數論+容斥
題目地址:?
POJ 1150
題意:?
求排列P(n, m)后面第一個非0的數。
分析:
為了熟悉題目中的理論。我先做了倆0基礎的題目:?
POJ 1401。題解見:POJ 1401 && ZOJ 2202 Factorial 階乘N!的末尾零的個數?
NYOJ 954。題解見:NYOJ 954 求N!二進制末尾幾個0
這題想了一下。十進制末尾幾個0能夠轉化為幾個5因子。二進制最后一位非0能夠轉化為2因子。可是10進制就不行了,并且這個不是單單N!。而是n!/m!。orz。?
實在太弱僅僅能研究題解,推薦SCAU_Lyon巨巨的題解和abilitytao巨巨的題解。
然后我坐在電腦前面看了一晚上題解,最終。我發現我太弱了,我好不easy有點看懂了。
大概講一下吧。?
我們要把排列轉化成前面兩題的形式。?
P(n, m) = n!/(n-m)!,我們讓m = n - m直接按n!/m!做,也就是求m?(m+1)?(m+2)?....?n了。?
這時候,我們僅僅要統計在[m, n]這個范圍里面的數的最后一位即可了,假設直接去暴力會跪。由于我們不僅要統計每一個數的最后一位,另一些2和5因子混在數中,我們還要消掉那些因子,然后取末位。
?
于是要把2和5抽出來,然后就僅僅剩3,7,9,統計抽完后的3,7,9,然后還得記得:由于這里面2可能會比5多,所以要把多出來的2算出來。
僅僅要知道怎樣統計n!,就能統計排列。?
個中計算有非常厲害的技巧,表示orz。
一、計算n!中消除2,5后末位為x的公式為:?
f(n, x) = n/10 + (n%10>=x) + f(n/2, x) + f(n/2, 5) - f(n/10, x).?
解釋下:?
1. x限定3,7,9。?
2. n/10 + (n%10>=x)也就是:每十個數以內末數字是3,7,9在沒有除去2和5兩種因子前都僅僅會出現一次。?
3. 加上抽出2和5后的子問題。(這里跟前面兩題原理一樣)?
4. 抽出2和5的時候,會多抽出了一次10,這時候就要用容斥定理減去。
二、然后計算多余的2就比較easy理解了。就跟前面倆題一樣。求出2的個數和5的個數。減一下就是n!中多出來的2的個數了。
三、然后我們就能得到[m,n]中抽出2,5后末位為3,7,9的個數,以及多出來的2的個數了。
?
這時候假設直接while(cnt--)去算可能會超時+爆范圍。?
我們能夠發現2^n,3^n,7^n,9^n的末位都是有規律可尋的。于是就能直接算了。
具體細節見代碼。
代碼:
/* * Author: illuz <iilluzen[at]gmail.com> * File: 1150.cpp * Create Date: 2014-05-26 22:28:45 * Descripton: */#include <cstdio> #include <cstring>const int N = 2e5;int cnt3, cnt7, cnt9, cnt2; int n, m; int rec[10][N];// 計算n!中消除2,5后末位為x的數量 int f(int n, int k) {if (n < 1)return 0;if (n < N && rec[k][n] != -1)return rec[k][n];int ret = n / 10 + (n % 10 >= k) + f(n / 2, k) + f(n / 5, k) - f(n / 10, k);if (n < N)rec[k][n] = ret;return ret; }// 多出來的2的個數 int more(int n) {int num2 = 0, num5 = 0;int t = n;while (t != 0) {num2 += t / 2;t /= 2;}while (n != 0) {num5 += n / 5;n /= 5;}return num2 - num5; }int main() {memset(rec, -1, sizeof(rec));while (~scanf("%d%d", &n, &m)) {if (m == 0) {puts("1");continue;}m = n - m;cnt2 = more(n) - more(m);cnt3 = f(n, 3) - f(m, 3);cnt7 = f(n, 7) - f(m, 7);cnt9 = f(n, 9) - f(m, 9);// printf("%d %d %d %d\n", cnt2, cnt3, cnt7, cnt9);// 2 4 8 6if (cnt2-- == 0)cnt2 = 1;else if (cnt2 % 4 == 0)cnt2 = 2;else if (cnt2 % 4 == 1)cnt2 = 4;else if (cnt2 % 4 == 2)cnt2 = 8;elsecnt2 = 6;// 1 3 9 7if (cnt3 % 4 == 0)cnt3 = 1;else if (cnt3 % 4 == 1)cnt3 = 3;else if (cnt3 % 4 == 2) cnt3 = 9;elsecnt3 = 7;// 1 7 9 3if (cnt7 % 4 == 0)cnt7 = 1;else if (cnt7 % 4 == 1)cnt7 = 7;else if (cnt7 % 4 == 2)cnt7 = 9;elsecnt7 = 3;// 1 9if (cnt9 % 2 == 0)cnt9 = 1;elsecnt9 = 9;printf("%d\n", cnt2 * cnt3 * cnt7 * cnt9 % 10);}return 0; }
轉載于:https://www.cnblogs.com/ldxsuanfa/p/10481394.html
總結
以上是生活随笔為你收集整理的POJ 1150 The Last Non-zero Digit 数论+容斥的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JS坦克大战游戏
- 下一篇: 高通工具QXDM、QCAT和QPST关系