2017多校联合第二场 1006题 hdu 6050 Funny Function 递推公式 / 矩阵快速幂

来源:互联网 发布:国际漫游数据流量套餐 编辑:程序博客网 时间:2024/05/16 10:11

题目链接


题意:

Problem Description
Function Fx,ysatisfies:

For given integers N and M,calculate Fm,1 modulo 1e9+7.


思路:

1. 递推法

根据第二个式子可以用特征根算出来 F1,i = 1/3 * (2 ^ n - (-1) ^ n)

后面再一行行地推也就不难了

推出来

n 为奇数时,Fm.1 = 1/3 * ((2 ^ n - 1) ^ (m - 1) * 2 + 1)

n 为偶数时,Fm,1 = 1/3 * ((2 ^ n - 1) ^ (m - 1) * 2)


但是注意,/3 并不能直接除,而要乘以 3 的乘法逆元(这就是为什么我昨天一直WA还百思不得其解)


AC代码如下:

#include <cstdio>typedef long long LL;const LL mod = 1e9 + 7;LL n, m;LL poww(LL a, LL b) {    LL ret = 1;    while (b) {        if (b & 1) { ret *= a; ret %= mod; }        a *= a;        a %= mod;        b >>= 1;    }    return ret % mod;}void work() {    scanf("%I64d%I64d", &n, &m);    LL x = poww(2, n) - 1;    if (x < 0) x += mod;    LL add = poww(x, m - 1) * 2 % mod;    if (n & 1) add += 1;    add *= poww(3, mod - 2);    add %= mod;    printf("%I64d\n", add);}int main() {    int t;    scanf("%d", &t);    while (t--) work();    return 0;}


2. 矩阵快速幂

参见

官方博客

大佬的blog


AC代码如下:

#include <cstdio>typedef long long LL;const LL mod = 1e9 + 7;struct Matrix {    LL a[2][2];    Matrix(LL b = 0, LL c = 0, LL d = 0, LL e = 0) : a{b, c, d, e} {}    Matrix operator * (const Matrix& temp) const {        Matrix ret;        for (int i = 0; i < 2; ++i) {            for (int j = 0; j < 2; ++j) {                for (int k = 0; k < 2; ++k) {                    ret.a[i][j] += a[i][k] * temp.a[k][j] % mod;                    ret.a[i][j] %= mod;                }            }        }        return ret;    }    Matrix operator - (const Matrix& temp) const {        Matrix ret;        for (int i = 0; i < 2; ++i) {            for (int j = 0; j < 2; ++j) {                ret.a[i][j] = a[i][j] - temp.a[i][j];                ret.a[i][j] %= mod;            }        }        return ret;    }};Matrix poww(Matrix temp, LL n) {    Matrix ret(1, 0, 0, 1);    while (n) {        if (n & 1) ret = ret * temp;        temp = temp * temp;        n >>= 1;    }    return ret;}void work() {    LL n, m;    scanf("%lld%lld", &n, &m);    Matrix temp = poww(Matrix(1, 2, 1, 0), n);//    printf("%lld %lld\n%lld %lld\n", temp.a[0][0], temp.a[0][1], temp.a[1][0], temp.a[1][1]);    Matrix ans(0, 0, 0, 0);    if (n & 1) ans = poww(temp - Matrix(0, 2, 1, -1), m - 1);    else ans = poww(temp - Matrix(1, 0, 0, 1), m - 1);    LL anss = ans.a[1][0] + ans.a[1][1]; anss %= mod;    printf("%lld\n", anss);}int main() {    int T;    scanf("%d", &T);    while (T--) work();    return 0;}



碎碎念:

乘法逆元什么的...

扎心了,昨天上午补第一场的12题时要求很大的数的组合数才看的

参见
组合数取模(逆元+快速幂)

阅读全文
0 0
原创粉丝点击