HDU 3221 Brute-force Algorithm(指数降幂公式)

题目链接;
HDU 3221 Brute-force Algorithm
题意:
根据递归可以得到 f[1]=a,f[2]=b,f[n]=f[n1]f[n2](n3) ,给出 a,b,p,n f[n]%p
数据范围: 1n1000000000,1P1000000,0a,b<1000000.
分析:
设菲波那切数列第 n 项为g[n],g[1]=0,g[2]=1,g[3]=1.根据递推可以得到:
f[n]=ag(n1)bg(n) %p  (n3)
但是考虑到指数 g(n) 会很大,我们需要降幂。
指数降幂公式:

Ax % p=Ax%ϕ(p)+ϕ(p) % p xϕ(p),ϕ(p)p

所以用矩阵快速幂求菲波那切数列时的取模数是 ϕ(p) 而不是 p

下面的代码用G++提交能 AC ,用 C++ 就不能。。。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <climits>
#include <cmath>
#include <ctime>
#include <cassert>
#include <bitset>
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
using namespace std;
typedef long long ll;
const int SIZE = 10;
const int MAX_N = 1000010;

bitset<MAX_N> bs;
int prime_cnt, prime[MAX_N], phi[MAX_N];

struct Matrix {
    int row, col;
    ll data[SIZE][SIZE];

    Matrix () {}
    Matrix (int _row, int _col): row(_row), col(_col) {}
};

void GetPhi()
{
    bs.set();
    prime_cnt = 0;
    phi[1] = 1;
    for(int i = 2; i < MAX_N; ++i) {
        if(bs[i] == 1) {
            prime[prime_cnt++] = i;
            phi[i] = i - 1;
        }
        for(int j = 0; j < prime_cnt && i * prime[j] < MAX_N; ++j) {
            bs[i * prime[j]] = 0;
            if(i % prime[j]) {
                phi[i * prime[j]] = (prime[j] - 1) * phi[i];
            }else {
                phi[i * prime[j]] = prime[j] * phi[i];
                break;
            }
        }
    }
}

Matrix matrix_mul(Matrix a, Matrix b, ll p)
{
    Matrix res;
    memset(res.data, 0, sizeof(res.data));
    res.row = a.row, res.col = b.col;
    for(int i = 1; i <= res.row; ++i) {
        for(int j = 1; j <= res.col; ++j) {
            for(int k = 1; k <= a.col; ++k) {
                res.data[i][j] += a.data[i][k] * b.data[k][j];
                if(res.data[i][j] > p) 
                    res.data[i][j] = (res.data[i][j] % p + p);
            }
        }
    }
    return res;
}

Matrix matrix_quick_pow(Matrix a, ll b, ll p)
{
    Matrix res, tmp = a;
    memset(res.data, 0, sizeof(res));
    res.row = res.col = a.row;
    for(int i = 1; i <= res.row; ++i) { res.data[i][i] = 1; }
    while(b) {
        if(b & 1) res = matrix_mul(res, tmp, p);
        tmp = matrix_mul(tmp, tmp, p);
        b >>= 1;
    }
    return res;
}

ll quick_pow(ll a, ll b, ll c)
{
    ll res = 1, tmp = a % c;
    while(b) {
        if(b & 1) res = res * tmp % c;
        tmp = tmp * tmp % c;
        b >>= 1;
    }
    return res;
}

int main()
{
    GetPhi();
    int T, cases = 0;
    ll a, b, p, n;
    scanf("%d", &T); 
    while(T--) {
        scanf("%lld%lld%lld%lld", &a, &b, &p, &n);
        if(n == 1) {
            printf("Case #%d: %lld\n", ++cases, a % p);
            continue;
        } else if(n == 2) {
            printf("Case #%d: %lld\n", ++cases, b % p);
            continue;
        } else if(n == 3) {
            printf("Case #%d: %lld\n", ++cases, a * b % p);
            continue;
        } else if(a == 0 || b == 0 || p == 1) {
            printf("Case #%d: %d\n", ++cases, 0);
            continue;
        }
        Matrix res, tmp;
        tmp.row = tmp.col = 2;
        tmp.data[1][1] = 0, tmp.data[1][2] = 1;
        tmp.data[2][1] = 1, tmp.data[2][2] = 1;
        res.row = 2, res.col = 1;
        res.data[1][1] = 0, res.data[2][1] = 1;

        tmp = matrix_quick_pow(tmp, n - 2, phi[p]);
        res = matrix_mul(tmp, res, phi[p]);

        ll ans = quick_pow(a, res.data[1][1], p);
        ans = ans * quick_pow(b, res.data[2][1], p) % p;
        printf("Case #%d: %lld\n", ++cases, ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值