您的位置:首页 > 编程语言 > Go语言

hdu 3221 Brute-force Algorithm 指数循环节

2013-07-31 12:51 232 查看
观察题目的程序可以很容易得到F[1] = a ,F[2] = b , F[3] = F[1]*F[2] , ....   F
= F[n-1]*F[n-2]

由于n <= 10^9,应该是要用到二分幂了,观察可得,F[1] = a, F[2] = b, F[3] = a*b , F[4] = a * b^2 , F[5] = a^2 * b^3,

也就是说a的次幂和b的次幂都是斐波那契数列,这样就很简单了,然后根据

A^x % m = A^(x%phi(m)+phi(m)) % m (x >= phi(m))

不清楚这个公式的可以戳这里看看http://blog.csdn.net/u010710717/article/details/9664825

a和b的次幂刚好是斐波那契数列中相邻的两个数,所以可以一次性得到,不过要判断下要不要加上Phi(m),具体见代码。

#include <stdio.h>
#define LL __int64

const int maxn = 100000;
bool vis[maxn];
int pri[maxn], num;
LL rec[2], q[2][2], qq[2][2], ss[2];

void get_prime() { // 素数筛选法
int i, j;
vis[1] = 1;
for(i = 2;i*i <= maxn; i++) if(!vis[i])
for(j = i*i;j <= maxn; j += i) vis[j] = 1;
num = 0;
for(i = 2;i <= maxn; i++) if(!vis[i])
pri[num++] = i;
}

LL euler(LL n) {
LL ans = n;
for(int i = 0;i < num && pri[i]*pri[i] <= n; i++) {
if(n%pri[i] == 0) {
ans = ans-ans/pri[i];
while(n%pri[i] == 0) n /= pri[i];
}
}
if(n > 1) ans = ans - ans/n;
return ans;
}

void recpow(LL mod, LL n) {
int i, j, k;
LL now1 = rec[0], now2 = rec[1];
int ok = 0;
for(i = 0;i < n; i++) {
LL now = now1 + now2;
if(now >= mod) {
if(i < n-1) ok = 2; // a和b的次幂都 >= mod
else ok = 1; // 唯独b的次幂 >= mod
break;
}
now1 = now2; now2 = now;
}
q[0][0] = 0;
q[0][1] = q[1][0] = q[1][1] = 1;
while(n) {
if(n&1) {
for(i = 0;i < 2; i++)
ss[i] = rec[0]*q[0][i] + rec[1]*q[1][i];
for(i = 0;i < 2; i++)
rec[i] = ss[i]%mod;
}
for(i = 0;i < 2; i++)
for(j = 0;j < 2; j++) {
qq[i][j] = 0;
for(k = 0;k < 2; k++)
qq[i][j] = (qq[i][j] + q[i][k]*q[k][j])%mod;
}
for(i = 0;i < 2; i++)
for(j = 0;j < 2; j++)
q[i][j] = qq[i][j];
n /= 2;
}
if(ok >= 1) rec[1] += mod;
if(ok >= 2) rec[0] += mod;
}

LL powmod(LL x, LL n, LL mod) {
LL ret = 1;
while(n) {
if(n&1) ret = ret*x%mod;
x = x*x%mod;
n /= 2;
}
return ret;
}

void solve(LL a, LL b, LL p, LL n) {
LL cur = euler(p); // 求模的欧拉函数
rec[0] = 0;rec[1] = 1;
recpow(cur, n); // 求a和b 的次幂
LL ans = powmod(a, rec[0], p);
ans = ans*powmod(b, rec[1], p)%p;
printf("%I64d\n", ans);
}

int main() {
get_prime();
LL a, b, p, n;
int t, cas = 1;
scanf("%d", &t);
while(t--) {
scanf("%I64d%I64d%I64d%I64d", &a, &b, &p, &n);
printf("Case #%d: ", cas++);
if(n == 1) printf("%I64d\n", a%p); //n <= 2 直接输出
else if(n == 2) printf("%I64d\n", b%p);
else solve(a, b, p, n-2);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: