0)
题意:t个测试案例,每一次输入n,求n^n的第一位数是几。(1<=n<=1,000,000,000)
分析:刚开始用大数模板,结果n>100,输出n^n时就已经在输出窗口连续输出了三行数字,10^9规模的n肯定不行;之后一直没做出来,比赛完看解题报告get到,大数是可以利用log来做以下转化,转化为10的幂的形式,进而分成10的整数部分×10的小数部分,从而方便得到首位数字,分析如下,耐心看完会发现很简单
m=n^n
log(10) m= log(10) n^n //两边分别求对10的对数
m=n^n=10 ^ (log(10) n^n) = 10 ^(n×log(10)n)
而此时的指数部分 n×log(10)n 可以化为(整数部分+小数部分)
m= 10 ^(n×log(10)n) = 10 ^(decimal + integer) = (10^decimal) × (10^integer) //decimal 小数的,integer整数的
而10^integer的首位数是1,所以m的首位应该是由10^decimal 的首位决定的,而decimal<1,所以 (10^decimal )<10,所以直接输出10^decimal即可。那么怎样将一个数的整数部分和小数部分分开呢,自己实现应该不难,但有现成的函数可以调用,<math.h>下的modf函数,
小数部分=modf(该数,&整数部分),注意 ,三个参数都用double类型。
double x,decimal,integer;
decimal=modf(x,&integer);
printf("数x分解成小数与整数之和,分解后:小数部分是%lf,整数部分是%lf",decimal,integer);
//大数计算中,我们需要注意中间的值是否会溢出,在下面的代码中,最大的中间的值应当是k*1.0*log10(k*1.0),1<k<10^9,0<log10(k)<9,所以0 < k*1.0*log10(k*1.0)< 9 × (10^9), 而double 范围是16位数字(包括小数,且默认拿出6位做小数的有效数字位数),如果全是整数则有16位有效数字,所以并没有超出double的表示范围,不会溢出。(而对程序的检测也的确如此,输入题目要求的10^9返回了正常值,输入10^15,这一步应当是(15*(10^15) ) ,大于10^15,返回了异常值。
1)
#include<stdio.h>
#include<math.h>
int main()
{
int t;
scanf("%d",&t);
int k;
while(t--){
scanf("%d",&k);
double decimal,integer;//小数部分,整数部分
decimal=modf(k*1.0*log10(k*1.0),&integer); //乘1.0变double类型
printf("%d\n",(int)pow(10,decimal));
}
}
2)
Description
Input
Each test case contains a single positive integer N(1<=N<=1,000,000,000).
Output
Sample Input
2 3 4
Sample Output
2 2
Hint
In the first case, 3 * 3 * 3 = 27, so the leftmost digit is 2. In the second case, 4 * 4 * 4 * 4 = 256, so the leftmost digit is 2.