题解 CF712E 【Memory and Casinos】
题目
原题目-CF712E
传送门
考场题目-HearthStone
Description
“低保不是挺轻松的吗?”
HS 需要智商,需要知己知彼,需要根据场面情况和对手策略进行针对性的概率分析和分类讨论。zzh 不擅长这些,看着hzy 又一次低保,便向 hzy 请教经验。
“每次你与对手博弈,获胜一局加一分,否则扣一分。低保之后,连胜附加分取消,上分的道路更加艰难。”,说着hzy 拿出一张足有七十米长的小纸条,“这是根据目前天梯上的情况得到的,我的卡组在已有
zzh 顿时来了劲,不停地问hzy,如果hzy 有一只小号目前有
为了避免精度问题,请输出在模P=998244353 域下的结果。
Input
第一行输入两个数,低保以上的分数上限
接下来
接下来
Output
对于所有zzh 的询问,一行一个数输出结果。
Sample Input
3 7
1 3
1 2
2 3
2 1 1
2 1 2
2 1 3
1 2 2 3
2 1 1
2 1 2
2 1 3
Sample Output
332748118
598946612
166374059
332748118
748683265
887328314
Hint
| 测试点编号 | 分值 | 对 |
其他限制 |
|---|---|---|---|
| 1 | 3 | 无 | |
| 2 | 22 | 无 | |
| 3 | 19 | 无 | |
| 4 | 24 | 无 | 无操作1,所有 |
| 5 | 6 | 无 | 无 |
| 6 | 26 | 无 | 无 |
如果P 是质数,那么
题解
注:本题考场题面与原题面不同,故考场思路中有些细节与原题不同,但是思路应该可取。
考场思路
可以将题目简化一下:
- 在一段有
n 个的连续的格子上,第i 个格子向右走的概率为p_i=\frac{x_i}{y_i} (显然向左走的概率为1-p_i ),现在给出Q 个询问或修改,修改会修改点d 的p_d 值,询问会询问从l 开始,不经过l-1 到r+1 的概率。
显然的一道概率
考虑当
更好的方案,设
注意,上式中的
其中
并且,还有
其中,
那么,我们将
我们移项之后有一个式子
这个式子中,前一项是常数项,我们不妨将其看做
令
又是一个关于
发现可以迭代,迭代到
可以解得
由于是线性递推,这个方法
考场代码
/* 44pts */
#include<cstdio>
#define cg (c=getchar())
inline int read(){
int x;bool f=true;char c;
while(cg<'0' || '9'<c)if(c=='-')f=false;
for(x=(c^48);'0'<=cg && c<='9';x=(x<<1)+(x<<3)+(c^48));
return f?x:-x;
}
#undef cg
const int MOD=998244353;
const int MAXN=1e5;
inline int inv(int x,int n=MOD-2){
int ret=1;
for(;n>0;n>>=1){
if(n&1)ret=1ll*ret*x%MOD;
x=1ll*x*x%MOD;
}return ret;
}
int f[MAXN+5];
int win[MAXN+5],fail[MAXN+5];
int N,Q;
inline void Init(){
N=read(),Q=read();
int x,y;
for(int i=1;i<=N;++i){
x=read(),y=read();
win[i]=1ll*x*inv(y)%MOD;
fail[i]=1ll*(y-x)*inv(y)%MOD;
}
}
inline void solve1(){
int opt,d,l,r;
int a,b;
while(Q--){
opt=read();
if(opt==1){
d=read(),l=read(),r=read();
win[d]=1ll*l*inv(r)%MOD;
fail[d]=1ll*(r-l)*inv(r)%MOD;
}else{
l=read(),r=read();
if(l==r){printf("%d\n",win[l]);continue;}
a=1,b=fail[l+1];
for(int i=l+1;i<=r;++i){
a=1ll*a*win[i-1]%MOD,b=1ll*b*win[i-1]%MOD;
b=(MOD+1-b)%MOD;
a=1ll*a*inv(b)%MOD;
/*if(i<r)*/b=1ll*fail[i+1]*inv(b)%MOD;
}
// a=1ll*a*win[r-1]%MOD,b=1ll*b*win[r-1]%MOD;
// b=(MOD+1-b)%MOD;
// a=1ll*a*inv(b)%MOD;
printf("%lld\n",1ll*a*win[r]%MOD);
}
}
}
signed main(){
// freopen("hs.in","r",stdin);
// freopen("hs.out","w",stdout);
Init();
solve1();
return 0;
}
/*
O(NQ):线性递推
O(Q logN):加上一些数据结构优化 ?
*/
正解
定义
然后我们定义
得到了递推式,现在看我们要求什么?
答案显然是
而我们又有
特殊规定:当
整理一下,我们就有
将
由定义,有
那么,我们现在唯一的问题就是
定义
由于我们对于这个式子有一个特殊规定,使得这个式子不是那么的规则,我们考虑将这个特殊规定的
这个式子现在看上去很整齐了,但是我们怎么维护?
考虑将后面那一项变换为前缀作差形式,用补项思想,那么有
那么就有
现在全部都是前缀的形式了,我们只需要维护
正解代码
被我咕掉了qwq