Queuing HDU - 2604 矩阵

一串字母,只有f,m,但是子串中不能有fmf ,fff 出现,


记答案为f[n],则易得f[0]=1,f[1]=2,f[2]=4,f[3]=6;f[[4]=9;

当长度为N时,若最后一个字符为M,前N-1个字符没有限制,即为F(N-1);

当最后一个字符串为F的时候,就必须去除最后3个字符是fmf和fff的情况(倒数第二个字符为F、M均有可能会不满

足情况),此时最后3个字符可能为mmf和mff;

当后3个字符为mmf时,前N-3个字符没有限制,即F(N-3);

但是当最后四个字符为mmff时,前N-4个字符无限制,即为F(N-4);

即f[n]=f[n-1]+f[n-3]+f[n-4];   

转化为矩阵即为:  

1 0 1 1       F(N-1)  F(N)      (即是f[n]=1*f[n-1]+0*f[n-2]+1*f[n-3]+1*f[n-4];)    
1 0 0 0  *    F(N-2)  = F(N-1)   (下面为单位矩阵)
0 1 0 0       F(N-3)  F(N-2)
0 0 1 0       F(N-4)  F(N-3)


矩阵快速幂,如果有多组数据,先写一个 EG ,一个初始的矩阵,每次pow(EG,n)就行,反正一开始就赋初值比较方便。

然后结构体的名称可以换一下,为 matrix ,方便记忆。

#include <bits/stdc++.h>
using namespace std;
typedef  long long ll;
int m;
struct node{
    ll a[4][4];
};
node EG={
        1,0,1,1,
        1,0,0,0,
        0,1,0,0,
        0,0,1,0
};
node mul(node A,node B){
    node C;
    memset(C.a,0,sizeof(C.a));
    for (int i = 0; i < 4; i++)
        for (int j = 0; j < 4; j++)
            for (int k = 0; k < 4; k++)
            {
                C.a[i][j] = (A.a[i][k] * B.a[k][j]%m+C.a[i][j])%m;
            }

    return C;
}
node pow(node A,int n){
    node B;
    memset(B.a,0,sizeof(B.a));
    for (int i = 0; i < 4; i++)
        B.a[i][i] = 1;
    while(n){
        if (n & 1) B = mul(B,A);
        A = mul(A,A);
        n >>= 1;
    }
    return B;
}
int main(){
    int n;
    node res;
    int a[4] = {1,2,4,6};
    while(scanf("%d%d",&n,&m) == 2){
        if (n == 0){
            printf("%d\n",1 % m);
            continue;
        }
        if (n == 1){
            printf("%d\n",2 %m);
            continue;
        }
        if (n == 2){
            printf("%d\n",4%m);
            continue;
        }
        n -=3;
        res = pow(EG,n);
        long long ans = 0;
        for (int i = 0; i < 4; i++){
            ans = (ans + res.a[0][i] * a[3-i]%m)%m;
        }
        printf("%lld\n",ans);
    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值