表达式求值 [思维题, 矩阵快速幂]

表 达 式 求 值 表达式求值



正 解 部 分 \color{red}{正解部分}

按顺序扫表达式, 记录四个状态,

S : 上 一 个 加 号 前 的 总 和 S: 上一个加号前的总和 S:
M : 上 一 个 加 号 到 最 后 一 个 乘 号 为 止 的 乘 积 M: 上一个加号到最后一个乘号为止的乘积 M:
T : 上 一 个 加 号 之 后 的 运 算 结 果 T: 上一个加号之后的运算结果 T:
e : 1 e: 1 e:1

当前位置的字符为 c i c_i ci,

c i =   ′ + ′ :       ( S , M , T , e ) → ( S + T , e , 0 , e ) c_i =\ '+':\ \ \ \ \ (S, M, T, e) \rightarrow (S+T, e, 0, e) ci= +:     (S,M,T,e)(S+T,e,0,e)
c i =   ′ × ′ :       ( S , M , T , e ) → ( S , T , 0 , e ) c_i =\ '\times':\ \ \ \ \ (S,M,T,e) \rightarrow (S, T, 0, e) ci= ×:     (S,M,T,e)(S,T,0,e)
c i =   数 字 k : ( S , M , T , e ) → ( S , M , 10 T + k M , e ) c_i =\ 数字k: (S, M, T, e) \rightarrow (S, M, 10T+kM, e) ci= k:(S,M,T,e)(S,M,10T+kM,e)

矩阵快速幂 加速转移, 最后 S + T S+T S+T 即为答案 .


实 现 部 分 \color{red}{实现部分}

#include<bits/stdc++.h>
#define reg register

const int mod = 998244353;

struct Matrix{
        int C[5][5];
        Matrix(){ memset(C, 0, sizeof C); }
} add, mul, num, Ans;

Matrix modify(const Matrix &a, const Matrix &b){
        Matrix res;
        for(reg int i = 1; i <= 4; i ++)
                for(reg int j = 1; j <= 4; j ++)
                        for(reg int k = 1; k <= 4; k ++)
                                res.C[i][j] = (1ll*res.C[i][j] + (1ll*a.C[i][k]*b.C[k][j]%mod)) % mod;
        return res;
}

Matrix Ksm(Matrix a, int b){
        Matrix res;
        for(reg int i = 1; i <= 4; i ++) res.C[i][i] = 1;
        while(b){
                if(b & 1) res = modify(res, a);
                a = modify(a, a); b >>= 1;
        }
        return res;
}

int N;
int r;

char s[20];

void Work(){
        scanf("%d%s", &r, s+1);
        int len = strlen(s+1);
        Matrix Mmp;
        for(reg int i = 1; i <= 4; i ++) Mmp.C[i][i] = 1;
        for(reg int i = 1; i <= len; i ++){
                if(s[i] == '+') Mmp = modify(Mmp, add);
                else if(s[i] == '*') Mmp = modify(Mmp, mul);
                else num.C[2][3] = s[i]-'0', Mmp = modify(Mmp, num);
        }
        Mmp = Ksm(Mmp, r); Ans = modify(Ans, Mmp);
}

int main(){
        add.C[1][1] = add.C[3][1] = add.C[4][2] = add.C[4][4] = 1;
        mul.C[1][1] = mul.C[3][2] = mul.C[4][4] = 1;
        num.C[1][1] = num.C[2][2] = num.C[4][4] = 1, num.C[3][3] = 10;
        Ans.C[1][2] = Ans.C[1][4] = 1; //
        scanf("%d", &N);
        for(reg int i = 1; i <= N; i ++) Work();
        Ans = modify(Ans, add);
        printf("%d\n", Ans.C[1][1]);
        return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值