UVA 10061 How many zero's and how many digits ? (m进制,阶乘位数,阶乘后缀0)

题意:给出两个数字a和b,求a的阶乘转换成b进制后,输出(1)后缀中有多少个连续的0?  (2)有多少位?

思路:逐个问题解决。

  设a!=k。  k暂时不用直接转成b进制。

(1)阶乘后缀0问题。先看这个十进制后缀0的例子:http://www.cnblogs.com/xcw0754/p/4604473.html

  解法差不多,稍变化。 首先将b分解成若干质数(比如8={2*2*2})保存在一个集合A中(注意自然数的质数分解是唯一的),只要有一个序列A就能构成一个0,因为满b就进位,b可以表示成10,表示一个1*b+0。那么我们需要知道k中究竟有多少个集合A。将k也质数分解成集合B,在集合B中每次减去一个A,每成功减掉1个A就有1个后缀0。

  直接求a!不是会爆吗?是的。将k进行质数分解和将{1~a}进行质数分解是一样的。那么就遍历[1,a]逐个进行分解,注意大于b的质数就不用去求了,其不可能用来组成b的。求完的质数的集合B应该是2有几个,3有几个,5有几个,7有几个...。如果集合A中需要4个2,那就看B中有多少个2,每两个2就可以组成一个后缀0,如果B中有5个2,那么就有2个0啦。

  总之,这步需要将b质数分解成A,将[1,a]质数分解成集合B,再看B中有多少个A。

(2)阶乘的位数问题。

  先举个例子: 一个三位数n满足102 <= n < 103

  那么他的位数w 满足 w = log103 = 3。 因此只要求lgn 向下取整 +1就是位数后因为阶乘比如5阶乘的话是5 * 4 * 3 * 2 * 1。他的位数就满足lg5 * 4 * 3 * 2 * 1 = lg5 + lg4 + lg3 + lg2 + lg1 这里用相加的就不会超过数字上限。

  当然这是十进制下得。如果是m进制下,就把log10n 换成logm就可以了。用高中知识:logm(n)的表示方法是 lgn / lgm。 这里有个double向下取整精度的问题要注意:转换成int时候,要floor(算出来的位数 + 1e-9) + 1.    注意:1e-9不要用变量存起来。

  最后得出位数的计算方式为:floor( logmn + logm(n - 1) + ...+ logm1 + 1e-9) + 1.红色部分就是所要算的主要数字,用一个循环累加即可。

 1 #include <bits/stdc++.h>
 2 #define LL long long
 3 using namespace std;
 4 const int N=2147483647;
 5 //const int mod=1e-9;   切记不能存起来,存起来时已经是个不精确值了。
 6 int has[999];  //哈希
 7 int need[999]; //进制的分解
 8
 9 int second(int a,int b)    //总位数
10 {
11     double tmp=0.0;
12     for(int i=2; i<=a; i++)    tmp+=log10(i);
13     if(b!=10)    tmp/=log10(b);     //转进制,10没必要转
14     return floor(tmp + 1e-9)+1;
15 }
16
17 int first(int a,int b)     //后缀0个数
18 {
19     memset(has,0,sizeof(has));
20     memset(need,0,sizeof(need));
21     for(int i=2; i<=a; i++)             //先分解阶乘中每个数
22     {
23         int t=i;
24         for(int j=2; j<=t&&j<=b; j++)   //质数为j
25         {
26             while(t%j==0)               //能被j整除的,全部除掉
27             {
28                 has[j]++;
29                 t/=j;
30             }
31         }
32     }
33     int t=b;
34     for(int i=2; i<=b; i++)      //进制b进行分解
35     {
36         while(t%i==0)
37         {
38             need[i]++;          //需要质数的个数记录起来
39             t/=i;
40         }
41     }
42
43     int cnt=N;
44     for(int i=2; i<=b; i++)
45         if(need[i]>0)    cnt=min(cnt,has[i]/need[i]);    //木桶原理,最低的一块木板起作用
46     return (cnt>=N?0:cnt);
47 }
48
49
50
51 int main()
52 {
53     //freopen("e://input.txt", "r", stdin);
54     int a, b;
55     while(~scanf("%d%d",&a,&b))
56         printf("%d %d\n", first(a,b), second(a,b));
57     return 0;
58 }

AC代码

UVA 10061 How many zero's and how many digits ? (m进制,阶乘位数,阶乘后缀0)

时间: 2024-10-24 16:46:04

UVA 10061 How many zero's and how many digits ? (m进制,阶乘位数,阶乘后缀0)的相关文章

UVA - 10061 How many zero&#39;s and how many digits ?

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=19099 给定一些点,求构成三角形最大面积,并且这个三角形不能不能包含其他点(在边上也不行). 因为数据范围很小,所以直接枚举就好,并且还把面积公式告诉了我们,判断点在三角形内的方法是,这个点与其他顶点的面积之和是否等于这个三角形的面积. #include<cstdio> #include<cmath> struct point { char z; int x,

UVA - 10061 How many zero&amp;#39;s and how many digits ?

n!=x*b^y, 当x为正整数时,最大的y就是n!末尾0的个数了, 把n,b分别拆成素因子相乘的形式: 比如, n=5,b=16 n=5,b=2^4, 非常明显,末尾0的个数为0 10进制时,n!=a*10^x b进制时,n!=c*b^y 非常明显,n!的位数就是最大的x+1 这里计算我用了log,精度设置为1e-9 #include<iostream> #include<cstdio> #include<vector> #include<cstring>

UVA 948 数的斐波那契进制表示

每个正整数都可以分解成斐波那契数列中的几个数相加-- 从大到小贪心法就可以了-- #include <iostream> #include <cstdio> #include <fstream> #include <algorithm> #include <cmath> #include <deque> #include <vector> #include <queue> #include <string

uva 10061(数学)

题解:题目要在b进制下输出的是一个数字阶乘后有多少个零,然后输出一共有多少位.首先计算位数,log(n)/log(b) + 1就是n在b进制下有多少位,而log有个公式就是log(M×N) = logM + logN,n! 的位数用公式可以化为( log(1) + log(2) +...+log(n) ) / log(b) + 1,为了精确再加 10^-6.阶乘后的零的数量计算是根据进制数的最大质因数和其数量确定的,比如10 = 2 × 5,所以10进制的最大质因数是5,数量是num = 1,例

Uva 1103 古代象形符号(dfs求连通块, floodfill, 进制转换)

题意: 给定一个H行W列的字符矩阵(H<200, W < 50), 输入的是一个十六进制字符, 代表一行四个相邻的二进制, 1代表像素, 0代表没有像素. 然后要求判断输入的是以下哪些图形,注意图形可以伸缩变换, 但不能拉断. 分析: 因为图形可以伸缩变换, 所以只要关注每个图形的特征, 题目表中的6个符号从左到右依次有1,3,5,4,0,2个白洞 我们先把十六进制还原成二进制建一幅图, 然后上下各留空一行, 左右各留空一列, 先把最外面的白色floodfill了(增加两行两列后保证外面的白色

UVA - 1412 状压dp九进制表示状态

此题难点在于用九进制表示状态,并且转移 这里九进制用vector表示,再用map作为此状态特有的标记 此处用刷表法,每一种状态转移都经历一遍,最终状态就是正确答案,注意界限 #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<map> #include<stack> #include<queue> #include&

UVA 11651 - Krypton Number System(DP+矩阵快速幂)

UVA 11651 - Krypton Number System 题目链接 题意:给一个进制base,一个分数score求该进制下,有多少数满足一下条件: 1.没有连续数字 2.没有前导零 3.分数为score,分数的计算方式为相邻数字的平方差的和 思路:先从dp入手,dp[i][j]表示组成i,最后一个数字为j的种数,然后进行状态转移,推出前面一步能构成的状态,也就是到dp[(b - 1) * (b - 1)][x]. 然后可以发现后面的状态,都可以由前面这些状态统一转移出来,这样就可以利用

UVA 10746 Crime Wave – The Sequel(费用流)

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1687 ProblemG CrimeWave – The Sequel Input: StandardInput Output: StandardOutput TimeLimit: 2 Seconds n bankshave been robbed this fine day. m (grea

uva 11317 - GCD+LCM(欧拉函数+log)

题目链接:uva 11317 - GCD+LCM 题目大意:给定n,求出1~n里面两两的最大公约的积GCD和最小公倍数的积LCM,在10100进制下的位数. 解题思路:在n的情况下,对于最大公约数为i的情况又phi[n/i]次.求LCM就用两两乘积除以GCD即可. #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; ty