求n^k的前任意位和后任意位

You are given two integers: n and k, your task is to find the most significant three digits, and least significant three digits of nk.

**Input
Input starts with an integer T (≤ 1000), denoting the number of test cases.
Each case starts with a line containing two integers: n (2 ≤ n < 231) and k (1 ≤ k ≤ 107).

Output
For each case, print the case number and the three leading digits (most significant) and three trailing digits (least significant). You can assume that the input is given such that nk contains at least six digits.

Sample Input

5
123456 1
123456 2
2 31
2 32
29 8751919

Sample Output

Case 1: 123 456
Case 2: 152 936
Case 3: 214 648
Case 4: 429 296
Case 5: 665 669**

题意:求n^k的前三位和最后三位

求后三位的思路:快速幂+求模,如果不懂快速幂板子的请看大佬的详解
如果b实在是超级大,也可以先用欧拉降幂使b减小,然后在使用快速幂+求模,当然该题不降低b也可以过,如果想了解,就看一下代码3

ll quickpowtrail(ll x,ll y,ll z)
{//表示求x^y%z
	ll ans=1;
	while(y)
	{
		if(y&1)
			ans=ans*x%z;
		x=x*x%z;
		y/=2;
	}
	return ans%n;
}

求前三位有两种思路:

思路1:与快速幂+求模的类似,只是稍微做下改动

double quickpowlead(ll a,ll y,ll z)
{//这里强调x,ans为浮点数
	double x=(double)a;
	double ans=1.0;
	while(y)
	{
		if(y&1)
		{
			ans=ans*x;
			while(ans>=z)
			ans/=10;//重点:ans必须是浮点数,每次除以10要保留小数部分 
		}
		x=x*x;
		y/=2;
		while(x>=z)
		x/=10;//重点:x必须是浮点数,每次除以10要保留小数部分  
	}
	return ans;
}

思路2:数学方法,很简单,也很短,也很容易理解

有一点需要知道:10^z可以任意表示一个整数,前提z可以是浮点数
	接下来n^k=10^z
	log10(n^k)=log10(10^z);
	z=k*log10(n);
	拆z=x+y;(x取整数,y取小数)
	10^z=10^(x+y)=10^x*10^y
	明显10^x指数控制位数,10^y控制的是每位上的数字
	第一步求:z=k*log10(n)
	第二步:x=(int)z;
	第三步:y=z-x;
	第四步:trail=(int)(10^y*100)
	结束
		double z=1.0*k*log10(n*1.0);
		ll x=(ll)z;
		double y=z-x;
		ll lead=(ll)(pow(10,y)*100)

全部代码
代码1:

#include<stdio.h>
#include<math.h>
typedef long long ll;
double quickpowlead(ll a,ll y,ll z)
{
	double x=(double)a;
	double ans=1.0;
	while(y)
	{
		if(y&1)
		{
			ans=ans*x;
			while(ans>=z)
			ans/=10;//重点:ans必须是浮点数,每次除以10要保留小数部分 
		}
		x=x*x;
		y/=2;
		while(x>=z)
		x/=10;//重点:x必须是浮点数,每次除以10要保留小数部分  
	}
	return ans;
}
ll quickpowtrail(ll x,ll y,ll z)
{
	ll ans=1;
	while(y)
	{
		if(y&1)
			ans=ans*x%z;
		x=x*x%z;
		y/=2;
	}
	return ans;
}
int main()
{
	ll t,cs;
	scanf("%lld",&t);
	for(cs=1;cs<=t;cs++)
	{	
		ll n,k;
		scanf("%lld %lld",&n,&k);              
		ll lead=quickpowlead(n,k,1000);
		ll trail=(ll)quickpowtrail(n,k,1000);
		printf("Case %d: %lld %03lld\n",cs,lead,trail);	
	}
	return 0;
} 

代码2:

#include<stdio.h>
#include<math.h>
typedef long long ll;
ll quickpow(ll x,ll y,ll z)
{
	ll ans=1;
	while(y)
	{
		if(y&1)
			ans=ans*x%z;
		x=x*x%z;
		y/=2;
	}
	return ans;
}
int main()
{
	int t,cs;
	scanf("%d",&t);
	for(cs=1;cs<=t;cs++)
	{	
		int n,k;
		scanf("%d %d",&n,&k);
		
		double z=1.0*k*log10(n*1.0);
		ll x=(ll)z;
		double y=z-x;
		ll lead=(ll)(pow(10,y)*100);//10^y
		
		ll trail=quickpow(n,k,1000);
		printf("Case %d: %lld %03lld\n",cs,lead,trail);
		
	}
	return 0;
} 

代码3:

#include<stdio.h>
#include<math.h>
typedef long long ll;
ll phi(ll n)
{//求1,n-1内与n互质的个数 
	ll i,rea=n;
	for(i=2;i*i<=n;i++)
	{
		if(n%i==0)
		{
			rea=rea-rea/i;
			while(n%i==0)
				n/=i;
		}	 
	}
	if(n>1)
		rea=rea-rea/n;
	return rea;
}

ll quickpow(ll x,ll y,ll z)
{
	ll ans=1;
	while(y)
	{
		if(y&1)
			ans=ans*x%z;
		x=x*x%z;
		y/=2;
	}
	return ans;
}
int main()
{
	int t,cs;
	scanf("%d",&t);
	for(cs=1;cs<=t;cs++)
	{	
		int n,k;
		scanf("%d %d",&n,&k);
		
		double z=1.0*k*log10(n*1.0);
		ll x=(ll)z;
		double y=z-x;
		ll lead=(ll)(pow(10,y)*100);//10^y
		
		ll rea=phi(1000);
		ll trail=quickpow(n,k%rea+rea,1000);
		
		注意k%rea+rea
		公式:a^b%c==a^(b%rea+rea)%c,
		如若了解为什么,就网上搜搜欧拉函数的解释吧
		
		printf("Case %d: %lld %03lld\n",cs,lead,trail);
		
	}
	return 0;
} 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值