A. A simple Problem(2019武大校赛现场赛)(吉比特杯第二届湖北省程序设计大赛) 解题报告 Apare_xzc

A. A simple Problem(2019武大校赛现场赛)(吉比特杯第二届湖北省程序设计大赛) 解题报告

xzc 2019/4/15


题意:

求下列式子,其中有K个b

((((a)^b)^b)^b...)^b  % p

数据范围:
  1<=a,b,p<=1E7
  1<=k<=1E18


输入:
  第一行一个T,代表T组数据
  下面有T行,每行4个数,a,b,k,p


输出:
T行,每行一个整数


样例输入:

3
2 3 1 10000
3 2 2 80
342 234 567 89

样例输出:

8
1
2

思路:

拓展欧拉定理:

a^b%p = a^(b%phi[p]+phi[p]) % p   ( b>phi[p] )

a^b%p = a^(b%phi[p]) % p   ( b<=phi[p] )

  • Phi[p]的衰减速度很快,不到100次就会变为1,然后任意数%1=0
  • 所以我们递归求解即可
  • 判断k个b的幂是否>p可以在求快速幂时,顺便处理出来
  • 具体见代码

我的代码:

/* Author: xzc time: 723ms status:AC A. A simple problem */
#include<bits/stdc++.h>
#define For(i,a,b) for(register int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(register int i=(a);i>=(b);--i)
#define Mst(a,b) memset(a,(b),sizeof(a))
#define LL long long
using namespace std;
const int maxn  =1e7+100;
int sushu[maxn/10];
bool notPrime[maxn];
int phi[maxn];
void getPhiTable(int * p); 
LL fast_pow(bool & ok,LL a,LL b,LL m)  
{   //快速幂,oK用于返回a^b是否大于m 
	ok = false;
	LL ans = 1;
	while(b)
	{
		if(b&1)
		{
			ans = ans*a;
			if(ans>m) ok = true;
			if(ans>=m) ans %= m;	
		} 
		a = a*a;
		if(a>m) ok = true;
		if(a>=m) a%=m;
		b>>=1; 
	}
	return ans;
}
LL f(bool & big,LL b,LL k,LL p,bool &flag) //求 (((b^b)^b)...) % p
{   //flag用于记录之前小于K个b的幂是否大于p 
	//printf("进入了第%lld层,要计算%lld个%lld %% %lld\n",k,k,b,p); 
	if(k==1)
	{
		if(b>p) b = b%p+p,flag = true;
		else b = b%p;
		return b;
	}
	if(p==1) return 1;
	bool ok = false;
	LL y = f(ok,b,k-1,phi[p],flag);
	if(ok||flag) y += phi[p],flag = true; 
	//printf("回到了第%lld层,要计算pow(%lld,%lld,%lld)\n",k,b,y,p); 
	return fast_pow(big,b,y,p); 
}
/* 4 87 2 77 83 29 2 53 57 9122259 6 57 57 50 4 35 9684961 Answer: 70 4 39 9211933 */
int main()
{
	//freopen("02.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	getPhiTable(phi);
	int T;
	LL a,b,p,k;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%lld%lld%lld%lld",&a,&b,&k,&p);
		int pp = phi[p];	
		bool ok = false;
		bool flag = false;
		LL zz = f(ok,b,k,pp,flag);///zzz = (((b^b)^b)...) % pp K个b 
		if(ok||flag) zz += pp;
		LL ans = fast_pow(ok,a,zz,p);
		printf("%lld\n",ans);
	}	
	return 0;
} 
void getPhiTable(int *p)
{
	int cnt = 0;
	int n = maxn-50;
	p[1] = 1;
	For(i,2,n)
	{
		if(!notPrime[i])
		{
			sushu[cnt++] = i;
			p[i] = i-1;		
		}
		for(int j=0;j<cnt&&1ll*i*sushu[j]<=n;++j)
		{
			notPrime[i*sushu[j]] = true;
			if(i%sushu[j])
				p[i*sushu[j]] = p[i]*(sushu[j]-1);
			else
			{
				p[i*sushu[j]] = p[i]*(sushu[j]);
				break;
			}
		}
	}	
}

全部评论

相关推荐

点赞 评论 收藏
分享
11-02 09:49
已编辑
货拉拉_测试(实习员工)
热爱生活的仰泳鲈鱼求你们别卷了:没事楼主,有反转查看图片
点赞 评论 收藏
分享
ArisRobert:统一解释一下,第4点的意思是,公司按需通知员工,没被通知到的员工是没法去上班的,所以只要没被通知到,就自动离职。就是一种比较抽象的裁员。
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务