题目
Takahashi布置了一个网页,
给定一个长为24的仅由A和T构成的字符串,表示每天整点能登进这个网页的概率
第i个字母如果是T,表示第i个整点的时候Takahashi有X(1<=X<=99)%的概率能登进去一次,
如果是A,表示第i个整点的时候Aoki有Y(1<=Y<=99)%的概率能登进去一次,
问如果在第一天的0点前把网页挂上去,第n(1<=n<=1e18)次登陆是由Aoki登进去的概率,
答案p/q,对998244353取模
思路来源
官方题解
题解
感觉主要是第一步概率化简就没想到,但是也是很基础的式子
首先要求第一次登陆是发生在第i小时的概率,
即等于第一天在第i小时登陆+第二天在第i小时登陆+...+第无穷天在第i小时成功登陆
而第二天在第i小时登陆的概率=第一天在第i小时登陆的概率*这一整天都没登进去的概率
是一个等比数列求和,考虑计q=这一整天都没登进去的概率
p1=第一天在第i小时登陆的概率
则ans[i]=p1(1+q+q^2+...)=p1*(1-q^无穷)/(1-q),
又24小时内的事件x、y的概率都大于0,小于1,所以q也在0和1之间,有ans[i]=p1/(1-q)
然后注意到计算p1的时候,实际是默认上一次登录是发生在23点的(0点前)
但有了一次登录之后,对于下一次登录来说,上一次登录就可能发生在[0,23]点的任意一个时刻了
所以,需要预处理dp[i][j]表示上一次登录是在第i时刻时,本次登录是在第j时刻的概率
这个时候,p1这个概率,也就是[i+1,j-1]时刻都登陆失败,而第j时刻登陆成功,
需要考虑跨天的情形
要求第n(n<=1e18)次登录的时候,矩阵快速幂优化一下就可以了,这里写成了类似快速幂的样子
第n次还需要是Aoki登录,所以只统计第n次时,字母是A的答案
代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=65,H=25,mod=998244353;
ll n;
int x,y,q,inv,sum,p[H];
int dp[N][H][H],ans[H],nans[H];
char s[H];
int modpow(int x,int n,int mod){
int res=1;
for(;n;n>>=1,x=1ll*x*x%mod){
if(n&1)res=1ll*res*x%mod;
}
return res;
}
int cal(){
ans[23]=1;
for(int i=0;n;n>>=1,i++){
if(n&1){
memset(nans,0,sizeof nans);
for(int j=0;j<24;++j){
for(int k=0;k<24;++k){
nans[k]=(nans[k]+1ll*ans[j]*dp[i][j][k]%mod)%mod;
}
}
memcpy(ans,nans,sizeof ans);
}
for(int j=0;j<24;++j){
for(int k=0;k<24;++k){
for(int l=0;l<24;++l){
dp[i+1][j][l]=(dp[i+1][j][l]+1ll*dp[i][j][k]*dp[i][k][l]%mod)%mod;
}
}
}
}
int res=0;
for(int i=0;i<24;++i){
if(s[i]=='A'){
res=(res+ans[i])%mod;
}
}
return res;
}
int main(){
cin>>n>>x>>y;
cin>>s;
q=1;
inv=modpow(100,mod-2,mod);
for(int j=0;j<24;++j){
int v=(s[j]=='A')?y:x;
p[j]=1ll*v*inv%mod;
q=1ll*q*(1-p[j]+mod)%mod;
}
sum=modpow(1-q+mod,mod-2,mod);//q<1 1*(1-q^n)/(1-q)
for(int las=0;las<24;++las){
int pre=1;
for(int add=0;add<24;++add){
int now=(las+add+1)%24;
int can=1ll*pre*p[now]%mod;
dp[0][las][now]=1ll*sum*can%mod;
pre=1ll*pre*(1-p[now]+mod)%mod;
}
}
cout<<cal()<<endl;
return 0;
}