poj 2109 && lightoj 1045(double的应用)

49 篇文章 0 订阅


A - Power of Cryptography
Time Limit:1000MS     Memory Limit:30000KB     64bit IO Format:%lld & %llu

Description

Current work in cryptography involves (among other things) large prime numbers and computing powers of numbers among these primes. Work in this area has resulted in the practical use of results from number theory and other branches of mathematics once considered to be only of theoretical interest. 
This problem involves the efficient computation of integer roots of numbers. 
Given an integer n>=1 and an integer p>= 1 you have to write a program that determines the n th positive root of p. In this problem, given such integers n and p, p will always be of the form k to the n  th. power, for an integer k (this integer is what your program must find).

Input

The input consists of a sequence of integer pairs n and p with each integer on a line by itself. For all such pairs 1<=n<= 200, 1<=p<10  101 and there exists an integer k, 1<=k<=10  9 such that k  n = p.

Output

For each integer pair n and p the value k should be printed, i.e., the number k such that k n =p.

Sample Input

2 16
3 27
7 4357186184021382204544

Sample Output

4
3
1234

题目大意: K ^ N = P, 给N 和 P, 求K。数据规模 :1<=n<= 200, 1<=p<10101 and there exists an integer k, 1<=k<=109 。


类型             长度 (bit)            有效数字                    绝对值范围 
float             32                      6~7                  10^(-37) ~ 10^38
double          64                     15~16               10^(-307) ~10^308
long double   128                   18~19                10^(-4931) ~ 10 ^ 4932

double的有效数字有15 - 16,这题恰好数据在有效范围以内,所以可以直接double运算;


一般思路:二分+高精度算法

 

但是本题还有一个更加巧妙的办法去处理:

首先需要明确:double类型虽然能表示10^(-307)   ~   10^308, (远大于题意的1<=p<10101这个范围),但只能精确前16位,因此必须慎用!

那么为了避免double对输入的数在运算过程中进行精确,那么我们必须让double的运算第一步就得到一个int(即小数点尾数全为0),这个不难理解。

 

然后根据题意,是求指数k,一般人自然想到利用 对数log,即k=lognp。但是不要忘记使用对数最大的问题就是没有lognp函数,只有log()函数(底数为e),为此要计算lognp就必须使用换底公式lognp=log(p)/log(n),即k= log(p)/log(n),由于这使得double的运算变为了3次,而且执行除法前的两次对数运算log的结果未必都是int,很显然k是一个被精确了的double

 

很多人到这里就放弃了使用double,转换方向到正常思路(二分+高精度算法),但是不要忘记求指数k除了使用对数log,还能使用指数的倒数开n次方,这时就可以用pow函数了

k=pow(p,1.0/n),double的运算一步到位,k自然也是一个int


<span style="color:#003300;">#include<iostream>  
#include<math.h>  
using namespace std;  
int main(void)  
{  
    double n,p;  
    while(cin>>n>>p)  
        cout<<pow(p,1.0/n)<<endl;  //指数的倒数就是开n次方  
    return 0;  
}  </span><span style="color:#ff0000;">
</span>


                                                                                1045 - Digits of Factorial
Time Limit: 2 second(s)Memory Limit: 32 MB

Factorial of an integer is defined by the following function

f(0) = 1

f(n) = f(n - 1) * n, if(n > 0)

So, factorial of 5 is 120. But in different bases, the factorial may be different. For example, factorial of 5 in base 8 is 170.

In this problem, you have to find the number of digit(s) of the factorial of an integer in a certain base.

Input

Input starts with an integer T (≤ 50000), denoting the number of test cases.

Each case begins with two integers n (0 ≤ n ≤ 106) and base (2 ≤ base ≤ 1000). Both of these integers will be given in decimal.

Output

For each case of input you have to print the case number and the digit(s) of factorial n in the given base.

Sample Input

Output for Sample Input

5

5 10

8 10

22 3

1000000 2

0 100

Case 1: 3

Case 2: 5

Case 3: 45

Case 4: 18488885

Case 5: 1



题意:f(n)只得是前n项的阶乘,求f(n)的k进制有多少位;

思路:求 n 的阶乘在 base 进制下的位数,log10(n)+ 1就是 n 的在十进制下的位数,由此可知 log base(n) 就是n在base 进制下的位数,再根据换底公式,log base(n) == log(n)/ log(base),这里让求的是阶乘,根据log的原理呢,就有log base (n!) == ( log(n) + log(n-1) + log(n-2) + 。。。。+ log(1)) / log(base)。用 sum 数组存一下 log(n!) 就可以快速的求出了

按照这个思路,log10代表以10为底,写如下程序

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#define CLR(a, b) memset(a, (b), sizeof(a))
using namespace std;
typedef long long LL;
const int MAXN = 1e6 +10;
const int INF = 0x3f3f3f3f;
double ans[MAXN];
int main()
{
    ans[0] = 0;
    for(int i = 1; i <= 1000000; i++) {
        ans[i] = ans[i-1] + log10(i*1.0);
    }
    int t, kcase = 1; scanf("%d", &t);
    while(t--) {
        int n, base; scanf("%d%d", &n, &base);
        if(n == 0) {
            printf("Case %d: 1\n", kcase++);
            continue;
        }
        printf("Case %d: %lld\n", kcase++, (LL)ceil(ans[n] / log10(base*1.0)));
    }
    return 0;
}
log函数以e为底,我们也可以直接用log函数,为什么呢,因为如果用log函数表示位数的话应该是:logkn = log10n / log 10 k= (log(n)/log(10)) / (log(k)/log(10)) = logn / logk

#include <iostream>  
#include <cstdio>   
#include <cmath>  
using namespace std;  
const int N=1000005;  
const int mod=1e9+7;  
double num[N];  
int main()  
{  
    int t,Case=0;  
    for(int i=1;i<=N-1;i++)  
    {  
        num[i]=num[i-1]+log(i);  
    }  
    scanf("%d",&t);  
    while(t--)  
    {  
        int n,base;  
        Case++;  
        scanf("%d %d",&n,&base);  
        int ans=floor(num[n]/log(base))+1;  
        printf("Case %d: %d\n",Case,ans);  
    }  
    return 0;  
}  



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值