[ABC271G] Access Counter 题解

发布时间 2024-01-02 23:23:22作者: MoyouSayuki

[ABC271G] Access Counter 题解

思路

挺难的 DP。

状态里面不能含有天数,只能从时间点入手,一眼矩阵快速幂所以考虑以登录次数作为阶段设计状态。

可以得到这个DP:\(g_{i ,j}\) 表示登录 \(i\) 次,且第 \(i\) 次登录在 \(j\) 时刻的概率。

转移可以考虑枚举上一个登录的时间点,注意到上一次登录可能在几天前,所以令 \(f(i, j)\) 表示上一次在 \(i\) 时登录这一次在 \(j\) 时登录的概率:

\[g_{i, j} =\sum_{k = 1}^{24}g_{i - 1, k}\times f(k, j) \]

考虑求 \(f(i, j)\),可以枚举之间间隔了多少天,如果登录时间差不超过一天,容易处理出 \(w(i, j)\) 表示一天内,\(i + 1\) 时到 \(j - 1\) 时没人登录的概率。

\[\begin{aligned} f_{i, j} = \sum_{k = 0}^{\infty}P^kw(i, j)p_j\\ f_{i ,j} = w(i ,j)p_j\sum_{k = 0}^{\infty}P^k\\ f_{i ,j} = \dfrac{w(i ,j)p_j}{1 - P} \end{aligned} \]

然后矩阵快速幂优化 \(g\) 的转移就可以了。

时间复杂度:\(O(h^3\log n)\)\(h = 24\)

// Problem: [ABC271G] Access Counter
// Contest: Luogu
// Author: Moyou
// Copyright (c) 2023 Moyou All rights reserved.
// Date: 2024-01-02 22:24:40

#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
typedef long long ll;
const int N = 25, mod = 998244353;

struct Mat {
    int m[N][N], r, c;
    void clear(int R, int C) {
        memset(m, 0, sizeof m);
        r = R, c = C;
    }
    void init() {
        for (int i = 1; i <= min(r, c); i++)
            m[i][i] = 1;
    }
    friend Mat operator*(const Mat a, const Mat b) {
        Mat res; res.clear(a.r, b.c);
        for (int k = 1; k <= a.c; k++)
            for (int i = 1; i <= a.r; i++)
                for (int j = 1; j <= b.c; j++)
                    res.m[i][j] = (res.m[i][j] + 1ll * a.m[i][k] * b.m[k][j] % mod) % mod;
        return res;
    }
    void print() {
        for(int i = 1; i <= r; i ++, cout << endl)
            for(int j = 1; j <= c; j ++)
                cout << m[i][j] << ' ';
    }
} M, A;
Mat qmi(Mat a, ll b) {
	Mat res; res.clear(a.r, a.c), res.init();
	while(b) {
		if(b & 1) res = res * a;
		b >>= 1;
		a = a * a;
	}
	return res;
}
int qmi(int a, ll b) {
	int res = 1;
	while(b) {
		if(b & 1) res = 1ll * res * a % mod;
		b >>= 1, a = 1ll * a * a % mod;
	}
	return res;
}
ll n;
int px, py, p[N], w[N][N], pall;
string s;
int f(int i, int j) {
    return 1ll * w[i][j] * p[j] % mod * qmi((1ll - pall + mod) % mod, mod - 2) % mod;
}
signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> n >> px >> py >> s;
    pall = 1;
    px = 1ll * px * qmi(100, mod - 2) % mod, py = 1ll * py * qmi(100, mod - 2) % mod;
    for(int i = 1; i <= 24; i ++) {
        p[i] = (s[i - 1] == 'T' ? px : py);
        pall = 1ll * pall * (1ll - p[i]) % mod;
    }
    for(int i = 1; i <= 24; i ++) {
        for(int j = 1; j <= 24; j ++) {
            int tmp = 1;
            for(int k = i % 24 + 1; k != j; k = k % 24 + 1) tmp = 1ll * tmp * (1ll - p[k]) % mod;
            w[i][j] = tmp;
        }
    }
    M.clear(24, 24), A.clear(24, 1);
    for(int i = 1; i <= 24; i ++)
        for(int j = 1; j <= 24; j ++)
            M.m[i][j] = f(j, i);
    A.m[24][1] = 1;
    A = qmi(M, n) * A;
    int ans = 0;
    for(int i = 1; i <= 24; i ++)
        if(s[i - 1] == 'A') ans = (1ll * ans + A.m[i][1]) % mod;
    cout << (ans + mod) % mod << '\n';

    return 0;
}