[Luogu] P4838 P哥破解密码

题目背景

P哥是一个经常丢密码条的男孩子。

在ION 8102赛场上,P哥又弄丢了密码条,笔试满分的他当然知道这可是要扣5分作为惩罚的,于是他开始破解ION Xunil系统的密码。

题目描述

定义一个串合法,当且仅当串只由A和B构成,且没有连续的3个A。P哥知道,密码就是长度为N的合法字符串数量对19260817取模的结果。但是P哥不会算,所以他只能把N告诉你,让你来算

至于为什么要对这个数取模,好像是因为纪念某个人,但到底是谁,P哥也不记得了

然而他忘记字符串长度N应该是多少了,于是他准备试M组数据。

题目解析

WA了两次。

递推题,在长度为n-1的合法串中有这几种:末尾有连续2个A,末尾有1个A,末尾不是A。

然后稍加思考就可以发现在长度为n的串中末尾连续2个A的可以由长度为n-1的合法串中末尾是1个A的得到。

类似的,末尾一个A的可以由末尾没有A的得到,末尾是B的能由所有状态得到。

所以我们构造出下面的矩阵三行分别表示末尾是B,末尾1个A,末尾2个A。

1,1,1

1,0,0

0,1,0

矩阵快速幂+取模即可。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const long long p = 19260817;

struct Matrix {
    long long m[10][10];
    long long sizx,sizy;
    void reset() {
        for(int i = 1;i <= sizx;i++) {
            for(int j = 1;j <=sizy;j++) {
                if(i == j) m[i][j] = 1;
                else m[i][j] = 0;
            }
        }
        return;
    }
    void clean() {
        memset(m,0,sizeof(m));
        return;
    }
} pro;

int T;
long long n,ans;
/*
1,1,1
1,0,0
0,1,0
*/
inline void init() {
    pro.sizx = 3, pro.sizy = 3;
    pro.clean();
    pro.m[1][1] = pro.m[1][2] = pro.m[1][3] = pro.m[2][1] = pro.m[3][2] = 1;
    return;
}

inline Matrix mul(Matrix x,Matrix y) {
    Matrix res;
       res.clean();
    res.sizx = x.sizx, res.sizy = y.sizy;
    for(register int i = 1;i <= x.sizx;i++) {
        for(register int j = 1;j <= y.sizy;j++) {
            for(register int k = 1;k <= x.sizy;k++) {
                res.m[i][j] += x.m[i][k] * y.m[k][j] % p;
                res.m[i][j] %= p;
            }
        }
    }
    return res;
}

inline Matrix quick_pow(Matrix x,long long y) {
    Matrix res;
    res.sizx = x.sizx; res.sizy = x.sizy;
    res.reset();
    while(y) {
        if(y & 1) res = mul(res,x);
        x = mul(x,x);
        y >>= 1;
    }
    return res;
}

int main() {
    scanf("%d",&T);
    while(T--) {
        scanf("%lld",&n);
        if(n == 1) {puts("2");continue;}
        else if(n == 2) {puts("4");continue;}
        else if(n == 3) {puts("7");continue;}
        init();
        Matrix final = quick_pow(pro,n);
        printf("%lld
",(final.m[1][1]+final.m[1][2])%p);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/floatiy/p/9842494.html