Contents

10进制矩阵快速幂-狼胆带你每天头铁一题-算法日常[9/100]

头铁来源

因为狼胆小编本人比较垃圾,所以只能每天带大家头铁一题简单常识题(大佬眼中的常识,我这个蒟蒻还只能头铁),希望能帮助到小白,那就很开心了

题目

题目链接

2019牛客多校5 B题

https://cdn.jsdelivr.net/gh/wolfdan666/BlogPic/%E7%AE%97%E6%B3%95/2019%E5%B9%B4%E5%A4%9A%E6%A0%A1/%E7%89%9B%E5%AE%A2/%E7%AC%AC%E4%BA%94%E5%9C%BA/B_ti.png

题解

理想中的草稿状态

https://cdn.jsdelivr.net/gh/wolfdan666/BlogPic/%E7%AE%97%E6%B3%95/2019%E5%B9%B4%E5%A4%9A%E6%A0%A1/%E7%89%9B%E5%AE%A2/%E7%AC%AC%E4%BA%94%E5%9C%BA/%E7%90%86%E6%83%B3%E8%8D%89%E7%A8%BF.png

真实的草稿状态

https://cdn.jsdelivr.net/gh/wolfdan666/BlogPic/%E7%AE%97%E6%B3%95/2019%E5%B9%B4%E5%A4%9A%E6%A0%A1/%E7%89%9B%E5%AE%A2/%E7%AC%AC%E4%BA%94%E5%9C%BA/%E7%8E%B0%E5%AE%9E%E8%8D%89%E7%A8%BF.png

dreammoon大佬的官方的题解也可以看看

https://cdn.jsdelivr.net/gh/wolfdan666/BlogPic/%E7%AE%97%E6%B3%95/2019%E5%B9%B4%E5%A4%9A%E6%A0%A1/%E7%89%9B%E5%AE%A2/%E7%AC%AC%E4%BA%94%E5%9C%BA/%E8%BF%99%E9%87%8C%E7%9A%84%E5%8D%95%E4%BD%8D%E6%98%AFbase%EF%BC%8C%E5%BA%95%E7%9A%84%E6%84%8F%E6%80%9D...%E4%BB%A5%E5%89%8D%E4%B8%80%E7%9B%B4get%E4%B8%8D%E5%88%B0%E6%A2%A6%E6%9C%88%E5%A4%A7%E4%BD%AC%E7%9A%84%E7%82%B9.png

AC代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include<bits/stdc++.h>
typedef unsigned long long ULL;
const int SIZE = 3000010;
ULL MOD;
char s[SIZE];
/*矩阵相乘,第一行乘以第一列,第一行乘以第二列……也可以使用for两重循环求*/
void mul(ULL* c1, ULL* c2, ULL *res){
    res[0] = (c1[0] * c2[0] + c1[1] * c2[2]) % MOD;
    res[1] = (c1[0] * c2[1] + c1[1] * c2[3]) % MOD;
    res[2] = (c1[2] * c2[0] + c1[3] * c2[2]) % MOD;
    res[3] = (c1[3] * c2[3] + c1[2] * c2[1]) % MOD;
}

int main() {
    int a,b;
    int x1,x2;
    scanf("%d%d%d%d", &x1, &x2, &a, &b);
    scanf("%s%llu",s, &MOD);
    int len = 0;
    /* 统计长度,并且把个位的值(即最后一位的值)减去1 */
    for(; s[len]; len++);
    s[len-1]--;
    /* 个位减掉了之后向前面借位 */
    for(int i = len - 1; i >= 0 && s[i] < '0'; i--){
        s[i] = '9';
        s[i-1]--;
    }
    ULL now0 = x1, now1 = x2;
    ULL d[4][4];
    d[0][0] = 0;
    d[0][1] = 1;
    d[0][2] = b;
    d[0][3] = a;
    for(int it = len - 1; it >= 0; it--){
        memset(d[1], 0, sizeof(ULL) * 12);
        /*A "常数"矩阵相乘4次*/
        for(int p = 1; p < 4; p++){
            mul(d[p-1], d[p-1], d[p]);
        }
        s[it] -= '0';
        for(int p = 0; p < 4; p++){
            if((s[it] >> p) & 1){
                ULL* ml = d[p];
                std::tie(now0, now1) = std::make_pair((ml[0] * now0 + ml[1] * now1) % MOD,(ml[2] * now0 + ml[3] * now1) % MOD);
            }
        }
        mul(d[1], d[3], d[0]);
    }
    printf("%llu\n", now1);
    return 0;
}

少量知识点

tie

pair是tuple的一个子集

每天一句叨叨

今天看到一禅小和尚: 我们尝遍生活的苦,却都只是为了过好平凡的一生

但我觉得如果自己明知道人生是苦,明知道人是基因的机器人(参见算法日常4的叨叨),却认认认真真地选择好好生活,这就是一种伟大,这就是自由,这就是自己的突破,就是自己的英雄!