[NOI2013] 矩阵游戏 题解

[NOI2013] 矩阵游戏

[NOI2013] 矩阵游戏

各位我是弱智石锤了。

题目可能不是很难但是有点细节要注意。

首先考虑行和列我们分别来看:

  • 对于列的情况我们只需要前一项即可递推。
  • 对于行的情况我们只需要上一项也可递推。

那么本质上题目就提示我们可以只保留一项进行矩阵快速幂。

不妨设答案矩阵是
[ 1 f m ] \left[ \begin{matrix} 1 & f_m \end{matrix} \right] [1​fm​​]
我们考虑首先递推同一行之后再递推列,最后一行单独拿出来处理。
[ [ 1 b 0 a ] m − 1 × [ 1 d 0 c ] ] n − 1 × [ 1 b 0 a ] m − 1 \left[ \left[ \begin{matrix} 1 & b \\ 0 & a \end{matrix} \right] ^ {m - 1} \times \left[ \begin{matrix} 1 & d \\ 0 & c \end{matrix} \right] \right] ^ {n - 1} \times \left[ \begin{matrix} 1 & b \\ 0 & a \end{matrix} \right] ^{m - 1} [[10​ba​]m−1×[10​dc​]]n−1×[10​ba​]m−1
注意 矩阵乘法不满足交换律,所以我们矩阵必须按照顺序进行计算。

之后还有一个问题就是 n , m n, m n,m 实际上是很大的,但是对于矩阵不一定有费马小定理。

我们考虑对于第一个矩阵的 m o d − 1 mod - 1 mod−1 次幂得到的矩阵:
[ 1 b × ( a m o d − 2 + a m o d − 3 + ⋯ + a 0 ) 0 a m o d − 1 ] \left[ \begin{matrix} 1 & b \times (a^{mod - 2} + a^{mod - 3} +\dots + a^0) \\ 0 & a^{mod - 1} \end{matrix} \right] [10​b×(amod−2+amod−3+⋯+a0)amod−1​]
我们发现 a m o d − 1 a^{mod - 1} amod−1 直接使用费马小定理得到是 1 1 1。

对于上面 b × ( a m o d − 2 + a m o d − 3 + ⋯ + a 0 ) b \times (a^{mod - 2} + a^{mod - 3} +\dots + a^0) b×(amod−2+amod−3+⋯+a0) 的部分,我们将里面的东西拿出来得到 a m o d − 1 − 1 a − 1 \dfrac{a^{mod - 1} - 1} {a - 1} a−1amod−1−1​ 。

如果 a = 1 a = 1 a=1 呢?直接带入可以得到当幂是 m o d mod mod 的时候上面的部分是 b × m o d b \times mod b×mod 那么也是单位矩阵了。

我们直接对于这个取模即可。

之后考虑 n n n 的限制,同理我们将
[ 1 b 0 a ] m − 1 × [ 1 d 0 c ] \left[ \begin{matrix} 1 & b \\ 0 & a \end{matrix} \right] ^ {m - 1} \times \left[ \begin{matrix} 1 & d \\ 0 & c \end{matrix} \right] [10​ba​]m−1×[10​dc​]
这个矩阵拿出来,发现左上角同样是 1 1 1 我们可以通过相同的方式得到。


#include <bits/stdc++.h>
using namespace std;

//#define Fread
//#define Getmod

#ifdef Fread
char buf[1 << 21], *iS, *iT;
#define gc() (iS == iT ? (iT = (iS = buf) + fread (buf, 1, 1 << 21, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
#define getchar gc
#endif // Fread

template <typename T>
void r1(T &x) {
	x = 0;
	char c(getchar());
	int f(1);
	for(; c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
	for(; '0' <= c && c <= '9';c = getchar()) x = (x * 10) + (c ^ 48);
	x *= f;
}

template <typename T,typename... Args> inline void r1(T& t, Args&... args) {
    r1(t);  r1(args...);
}

//#define int long long
const int maxn = 2e5 + 5;
const int maxm = maxn << 1;
int n, m;
const int mod = 1e9 + 7;
struct Matrix {
    int a[2][2];
    Matrix(void) { memset(a, 0, sizeof(a)); }
    Matrix operator * (const Matrix &z) const {
        Matrix res;
        for(int i = 0; i < 2; ++ i) {
            for(int j = 0; j < 2; ++ j) {
                for(int k = 0; k < 2; ++ k) {
                    res.a[i][j] = (res.a[i][j] + 1ll * a[i][k] * z.a[k][j] % mod) % mod;
                }
            }
        }
        return res;
    }
}F, tmp1, tmp2;
string sn, sm;
int A, B, C, D;

Matrix ksm(Matrix x,int mi) {
    Matrix res;
    res.a[0][0] = res.a[1][1] = 1;
    while(mi) {
        if(mi & 1) res = res * x;
        mi >>= 1;
        x = x * x;
    }
    return res;
}

signed main() {
//    freopen("S.in", "r", stdin);
//    freopen("S.out", "w", stdout);
    int i, j;
    cin >> sn >> sm;
    r1(A, B, C, D);// A <= C
    int mod1 = ( (A == 1) ? mod : mod - 1 );
    for(i = 0; i < sm.size(); ++ i)
        m = ( 10ll * m + (sm[i] ^ 48) ) % mod1;

//    printf("%d %d\n", n, m);

    F.a[0][0] = F.a[0][1] = 1;
    tmp1.a[0][0] = 1, tmp1.a[1][0] = 0;
    tmp1.a[0][1] = B, tmp1.a[1][1] = A;
    tmp2.a[0][0] = 1, tmp2.a[1][0] = 0;
    tmp2.a[0][1] = D, tmp2.a[1][1] = C;
    tmp1 = ksm(tmp1, m < 1 ? m + mod1 - 1 : m - 1);
    tmp2 = tmp1 * tmp2;
    mod1 = (tmp2.a[1][1] == 1 ? mod : mod - 1);
    for(i = 0; i < sn.size(); ++ i)
        n = ( 10ll * n + (sn[i] ^ 48) ) % mod1;
    F = F * ksm(tmp2, n < 1 ? n + mod1 - 1 : n - 1) * tmp1;
    printf("%d\n", F.a[0][1]);
	return 0;
}
/*
34578734657863487 38465873465876348 1 23734637 3892734 3849

467549493
*/
上一篇:解题报告 - 577. Employee Bonus


下一篇:P1397 [NOI2013]矩阵游戏