Skip to content

题解-P5137

Posted on:2023年7月18日 at 20:13

本文章遵守知识共享协议 CC-BY-NC-SA,同步发表于洛谷题解区,转载时须在文章的任一位置附上原文链接和作者署名(rickyxrc)。推荐在我的个人博客阅读。

题面大意

计算 (i=0naibni)modp(\sum\limits_{i=0}^na^ib^{n-i})\bmod p 的值。

解题思路

式子题。

我们定义 fi=j=0iajbijf_i = \sum\limits_{j=0}^ia^jb^{i-j},然后我们尝试推出一个递推式。

fi+1=j=0i+1ajbi+1j=j=0iajbi+1j+i+1b0=bj=0iajbij+ai+1=bfi+ai+1\begin{aligned}f_{i+1} &= \sum\limits_{j=0}^{i+1}a^jb^{i+1-j} \\&= \sum\limits_{j=0}^{i}a^jb^{i+1-j} + ^{i+1}b^{0} \\ &= b\sum_{j=0}^{i} a^jb^{i-j} + a^{i+1} \\ &= bf_i+a^{i+1} \end{aligned}

而这个递推式我们可以使用矩阵乘法进行加速。

具体地说,定义我们的状态矩阵为 [fiai]\begin{bmatrix}f_i \\ a^i\end{bmatrix},那么应该转移成 [bfi+ai+1ai+1]\begin{bmatrix}bf_i+a^{i+1} \\ a^{i+1}\end{bmatrix},中间乘的矩阵为 [ba0a]\begin{bmatrix}b & a \\ 0 & a\end{bmatrix}

答案就应该是 ([ba0a])n[11](\begin{bmatrix}b & a \\ 0 & a\end{bmatrix})^n\begin{bmatrix}1 \\ 1\end{bmatrix}(注意顺序哦)。

因为这道题的特殊性(略卡常),我就给出完整代码供参考。

#include <stdio.h>
#include <string.h>
#include <ctype.h>

typedef unsigned long long i64;
typedef __int128 i128;

inline i64 read()
{
    char c = getchar();
    i64 x = 0;
    for (; !isdigit(c); c = getchar())
        ;
    for (; isdigit(c); c = getchar())
        x = (x * 10) + (c - '0');
    return x;
}

inline void print(i64 x)
{
    if (x > 9)
        print(x / 10);
    putchar(x % 10 + '0');
}

struct matrix
{
    i64 c[4];
    matrix()
    {
        c[0] = c[1] = c[2] = c[3] = 0;
    }
};

i64 mod = -1, T, n, a, b, c, d;

#define pos00 .c[0]
#define pos01 .c[1]
#define pos10 .c[2]
#define pos11 .c[3]

inline matrix mutl(matrix a, matrix b)
{
    matrix res;
    res pos00 = (i128(a pos00) * b pos00 + i128(a pos01) * b pos10) % mod;
    res pos01 = (i128(a pos00) * b pos01 + i128(a pos01) * b pos11) % mod;
    res pos10 = (i128(a pos10) * b pos00 + i128(a pos11) * b pos10) % mod;
    res pos11 = (i128(a pos10) * b pos01 + i128(a pos11) * b pos11) % mod;
    return res;
}
matrix bm2, intl, A;

matrix fastpow(matrix num, i64 p)
{
    matrix res = bm2;
    while (p)
    {
        if (p & 1)
            res = mutl(res, num);
        num = mutl(num, num);
        p >>= 1;
    }
    return res;
}

int main()
{
    intl pos00 = 1;
    intl pos10 = 1;
    bm2 pos00 = 1;
    bm2 pos11 = 1;

    T = read();

    while (T--)
    {
        n = read();
        a = read();
        b = read();
        mod = read();

        A pos00 = b;
        A pos01 = a;
        A pos10 = 0;
        A pos11 = a;

        A = mutl(fastpow(A, n), intl);

        print(A pos00);
        putchar('\n');
    }
}


在 Rickyxrc's blog 出现的文章,若无特殊注明,均采用 CC BY-NC-SA 4.0 协议共享,也就是转载时需要注明本文章的地址,并且引用本文章的文章也要使用相同的方式共享。