Description
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
Output
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>
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;
}