传送门: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;
}