SDUT 2605 山东省第四届ACM省赛 A^X mod P (数论打表)

传送门:SDUT 2605



题目大意:

给你 7 个整数: n, A, K, a, b, m, P,以及一个 f(x) 的表达式:

f(x) = K, x = 1

f(x) = (a*f(x-1) + b)%m , x > 1

让你计算:( A^(f(1)) + A^(f(2)) + A^(f(3)) + ...... + A^(f(n)) ) modular P.


思路

一上来,我就暴力模拟,对于 A^f(x) 用快速幂求解,但是时间复杂度还是太高了,TLE……


正确的姿势是打表,因为 f(x) 中可能有很多数相同,所以没必要重复计算。但是 f(x) 最大 1e9,直接打表会 GG。所以可以把指数 f(x) 分解为 f(x) = ak+b,这样一来, A^f(x) = A^ak * A^b。


上式中的 k 和要打的表的大小有关,哪表开多大合适呢?理论上开 33333 就可以了,因为 sqrt(1e9) = 33333。这样只要计算 (A^1)%P 、(A^2)%P …… (A^33333)%P 以及 (A^1*33333)%P 、(A^2*33333)%P ……(A^33333*33333)%P ,对于 A^f(x),我们就可以通过上面两个数组相乘的结果得到了。



注意:

由于代码中涉及到乘法运算,所以 int 型会溢出,可以全部开 long long。



代码:

#include<stdio.h>
#include<string.h>
#define len 35000
typedef long long LL;

LL n,A,K,a,b,m,P;
LL dp1[len+10],dp2[len+10];
//dp1保存 (A^1)%P 、(A^2)%P …… (A^33333)%P
//dp2保存 (A^1*33333)%P 、(A^2*33333)%P ……(A^33333*33333)%P 

void init()
{ //打表 
	int i;
	dp1[0]=dp2[0]=1;	
	for(i=1;i<=len;i++) 
	{ 
		dp1[i]=(dp1[i-1]*A)%P;
	}
	dp2[1]=dp1[len];
	for(i=2;i<=len;i++)
	{
		dp2[i]=(dp2[i-1]*dp2[1])%P;
	}	
}

int main()
{
	LL i,t,f,cas,ans;
	scanf("%lld",&t);
	cas=1;
	while(t--)
	{
		scanf("%lld%lld%lld%lld%lld%lld%lld",&n,&A,&K,&a,&b,&m,&P);
		init();
		f=K;
		ans=0;
		for(i=1;i<=n;i++)
		{
			//将 A^f(x) 分解为 A^ak * A^b,其中 k即 len,a=f/len, b=f%len
			ans=(ans+(dp1[f%len]*dp2[f/len])%P)%P;  
			f=(a*f+b)%m; //生成下一个 f(x) 
		}
		printf("Case #%lld: %lld\n",cas++,ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zuzhiang/article/details/79985979