POJ 1150 The Last Non-zero Digit 数论+容斥

题目地址: 

id=1150" rel="nofollow" style="color:rgb(0,136,204);text-decoration:none;">POJ 1150

题意: 
求排列P(n, m)后面第一个非0的数。

分析:

为了熟悉题目中的理论。我先做了俩0基础的题目: 

id=1401" rel="nofollow" style="color:rgb(0,136,204);text-decoration:none;">POJ 1401。题解见:POJ
1401 && ZOJ 2202 Factorial 阶乘N!的末尾零的个数
 

pid=954" rel="nofollow" style="color:rgb(0,136,204);text-decoration:none;">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的末位都是有规律可寻的。于是就能直接算了。

具体细节见代码。

代码:

  1. /*
  2. * Author: illuz <iilluzen[at]gmail.com>
  3. * File: 1150.cpp
  4. * Create Date: 2014-05-26 22:28:45
  5. * Descripton:
  6. */
  7. #include <cstdio>
  8. #include <cstring>
  9. const int N = 2e5;
  10. int cnt3, cnt7, cnt9, cnt2;
  11. int n, m;
  12. int rec[10][N];
  13. // 计算n!中消除2,5后末位为x的数量
  14. int f(int n, int k) {
  15. if (n < 1)
  16. return 0;
  17. if (n < N && rec[k][n] != -1)
  18. return rec[k][n];
  19. int ret = n / 10 + (n % 10 >= k) + f(n / 2, k) + f(n / 5, k) - f(n / 10, k);
  20. if (n < N)
  21. rec[k][n] = ret;
  22. return ret;
  23. }
  24. // 多出来的2的个数
  25. int more(int n) {
  26. int num2 = 0, num5 = 0;
  27. int t = n;
  28. while (t != 0) {
  29. num2 += t / 2;
  30. t /= 2;
  31. }
  32. while (n != 0) {
  33. num5 += n / 5;
  34. n /= 5;
  35. }
  36. return num2 - num5;
  37. }
  38. int main()
  39. {
  40. memset(rec, -1, sizeof(rec));
  41. while (~scanf("%d%d", &n, &m)) {
  42. if (m == 0) {
  43. puts("1");
  44. continue;
  45. }
  46. m = n - m;
  47. cnt2 = more(n) - more(m);
  48. cnt3 = f(n, 3) - f(m, 3);
  49. cnt7 = f(n, 7) - f(m, 7);
  50. cnt9 = f(n, 9) - f(m, 9);
  51. // printf("%d %d %d %d\n", cnt2, cnt3, cnt7, cnt9);
  52. // 2 4 8 6
  53. if (cnt2-- == 0)
  54. cnt2 = 1;
  55. else if (cnt2 % 4 == 0)
  56. cnt2 = 2;
  57. else if (cnt2 % 4 == 1)
  58. cnt2 = 4;
  59. else if (cnt2 % 4 == 2)
  60. cnt2 = 8;
  61. else
  62. cnt2 = 6;
  63. // 1 3 9 7
  64. if (cnt3 % 4 == 0)
  65. cnt3 = 1;
  66. else if (cnt3 % 4 == 1)
  67. cnt3 = 3;
  68. else if (cnt3 % 4 == 2) cnt3 = 9;
  69. else
  70. cnt3 = 7;
  71. // 1 7 9 3
  72. if (cnt7 % 4 == 0)
  73. cnt7 = 1;
  74. else if (cnt7 % 4 == 1)
  75. cnt7 = 7;
  76. else if (cnt7 % 4 == 2)
  77. cnt7 = 9;
  78. else
  79. cnt7 = 3;
  80. // 1 9
  81. if (cnt9 % 2 == 0)
  82. cnt9 = 1;
  83. else
  84. cnt9 = 9;
  85. printf("%d\n", cnt2 * cnt3 * cnt7 * cnt9 % 10);
  86. }
  87. return 0;
  88. }

POJ 1150 The Last Non-zero Digit 数论+容斥的更多相关文章

  1. Coprime (单色三角形+莫比乌斯反演(数论容斥))

    这道题,先说一下单色三角形吧,推荐一篇noip的论文<国家集训队2003论文集许智磊> 链接:https://wenku.baidu.com/view/e87725c52cc58bd631 ...

  2. hdu1695:数论+容斥

    题目大意: 求x属于[1,b]和 y属于[1,d]的 gcd(x,y)=k 的方案数 题解: 观察发现 gcd()=k 不好处理,想到将x=x/k,y=y/k 后 gcd(x,y)=1.. 即问题转化 ...

  3. CROC 2016 - Elimination Round (Rated Unofficial Edition) F - Cowslip Collections 数论 + 容斥

    F - Cowslip Collections http://codeforces.com/blog/entry/43868 这个题解讲的很好... #include<bits/stdc++.h ...

  4. 数论 + 容斥 - HDU 4059 The Boss on Mars

    The Boss on Mars Problem's Link Mean: 给定一个整数n,求1~n中所有与n互质的数的四次方的和.(1<=n<=1e8) analyse: 看似简单,倘若 ...

  5. 数论 + 容斥 - HDU 1695 GCD

    problem's Link mean 给定五个数a,b,c,d,k,从1~a中选一个数x,1~b中选一个数y,使得gcd(x,y)=k. 求满足条件的pair(x,y)数. analyse 由于b, ...

  6. HDU - 2204 Eddy's爱好 (数论+容斥)

    题意:求\(1 - N(1\le N \le 1e18)\)中,能表示成\(M^k(M>0,k>1)\)的数的个数 分析:正整数p可以表示成\(p = m^k = m^{r*k'}\)的形 ...

  7. 【bzoj2393】Cirno的完美算数教室 数论容斥

    Description ~Cirno发现了一种baka数,这种数呢~只含有2和⑨两种数字~~ 现在Cirno想知道~一个区间中~~有多少个数能被baka数整除~ 但是Cirno这么天才的妖精才不屑去数 ...

  8. HDU 5514 Frogs (数论容斥)

    题意:有n只青蛙,m个石头(围成圆圈).第i只青蛙每次只能条ai个石头,问最后所有青蛙跳过的石头的下标总和是多少? 析:首先可以知道的是第 i 只青蛙可以跳到 k * gcd(ai, m),然后我就计 ...

  9. UOJ #129 / BZOJ 4197 / 洛谷 P2150 - [NOI2015]寿司晚宴 (状压dp+数论+容斥)

    题面传送门 题意: 你有一个集合 \(S={2,3,\dots,n}\) 你要选择两个集合 \(A\) 和 \(B\),满足: \(A \subseteq S\),\(B \subseteq S\), ...

随机推荐

  1. 795. Number of Subarrays with Bounded Maximum

    数学的方式 是对于所有的字符分成简单的三类 0 小于 L 1 LR 之间 2 大于R 也就是再求 不包含 2 但是包含1 的子数组个数 不包含2的子数组个数好求 对于连续的相邻的n个 非2类数 就有 ...

  2. np一些基本操作2

    import numpy as nparr1 = np.arange(32).reshape(8,4)print(arr1)arr1 = arr1.reshape(-1);print(arr1)arr ...

  3. LeetCode404Sum of Left Leaves左叶子之和

    计算给定二叉树的所有左叶子之和. 示例: 3 / \ 9    20 / \ 15   7 在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24 class Solution { pub ...

  4. GetCommandLine CmdLineToArgvW

    说明:LPTSTR GetCommandLine(VOID); LPWSTR * CommandLineToArgvW(                                        ...

  5. ERP或PLM系统-物料编码管理的技术实现

    1 企业现状 企业日常经营过程中会产生大量的文档,如设计图纸.变更单.计算书.设计方案等,如果是制造企业还会产生大量的产品.组成产品的零部件等物料,这些数据在进入信息系统前都需要有一个唯一的标识,也就 ...

  6. c++继承知识点小结

    继承的概念 继承是c++中一个重要的概念.继承是指,我们可以使用一个类来定义另一个类,在创建这个类时,我们就不需要重新编写数据成员与成员函数,这可以大大方便我们编写代码和维护代码的效率. 当我们使用一 ...

  7. 提示框插件layer的使用讲解

    官方网站:http://layer.layui.com/ 在页面中引入: <script src="js/layer-v3.0.3/layer/layer.js">&l ...

  8. CDA考试 ▏2017 CDA L1备考资源习题详解-统计基础部分

    CDA考试 ▏2017 CDA L1备考资源习题详解-统计基础部分 <CDA LEVEL 1描述性分析典型例题讲解> 主讲人:CDA命题组委会 傅老师 ▏2017 CDA L1备考资源习题 ...

  9. mybatis # $的区别

    1 #是将传入的值当做字符串的形式,eg:select id,name,age from student where id =#{id},当前端把id值1,传入到后台的时候,就相当于 select i ...

  10. FamilyFilter(4)

    3.1. 基于列族过滤数据的FamilyFilter 构造函数: FamilyFilter(CompareFilter.CompareOp familyCompareOp, ByteArrayComp ...