2021.08.16【2022省赛模拟】轮回
题目大意
在一个数轴上,每个时刻 (i) 有 (p_i) 的概率不动, (frac{1-p_i}{2}) 的概率往前一步, (frac{1-p_i}2) 的概率往后一步,活动范围不能超出 ([ -K , K ]) ( $ K le 5 $ ),时刻会循环,求从任意一个时刻 (0) 处开始,步数的期望。支持修改 $ p_i $ 。
解法一
设从 (S) 开始,将时刻和所在位置作为状态写出转移矩阵 (P_{ij}),
期望实际上就是每一步的概率之和,令 $ A = prod_{i=S}^n P imes prod_{i=1}^{S-1}P$ ,即转一圈的转移矩阵,那么这一时刻的概率就是一个无穷级数求和的形式,套用公式 (frac1{1-X}) 即可,最后要用到矩阵求逆, (A) 需要线段树维护,复杂度 $ O(n log n K^3) $ 。
解法二
同样写出转移矩阵,同样要求出 (A) ,同样线段树维护,设 (F_i) 为时刻为 (i) 处的期望步数(是个行向量),那么有 (F_iA = F_i) ,高斯消元解出即可,复杂度同样 (O(n log n K^3))
Hint
复杂度不太对劲。。。然而我们发现转移矩阵可以从 ((2K+1) imes (2K+1)) 压缩成 $ (K+1) imes (K+1)$ ,因为正负同样位置是等价的。这样复杂度就对了
Code
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define fo(i,a,b) for(register int i=a;i<=b;++i)
#define fd(i,a,b) for(register int i=a;i>=b;--i)
#define ll long long
#define ls (t<<1)
#define rs (t<<1|1)
using namespace std;
const int N=1e5+10;
const int mod=1e9+7;
int n,m,Q,len;
int p[N],q[N],ans[N],inv2;
void add(int &a,int b){a=(a+b>=mod?a+b-mod:a+b);}
void dec(int &a,int b){a=(a>=b?a-b:a-b+mod);}
struct matrix{
int a[8][8];
matrix(){
memset(a,0,sizeof(a));
fo(i,1,len)a[i][i]=1;
}
int* operator[](int x){return a[x];}
inline matrix operator*(matrix b){
matrix c;
fo(i,1,len){
fo(j,1,len){
c[i][j]=0;
fo(k,1,len)add(c[i][j] , 1ll * a[i][k] * b[k][j] % mod);
}
}
return c;
}
}tree[N*4],T;
inline int power(ll x,int n){
ll a=1;
while(n){
if(n&1)a=a*x%mod;
x=x*x%mod;
n>>=1;
}
return a;
}
void build(int t,int l,int r){
if(l==r){
fo(i,1,len-1){
tree[t][i][i]=p[l];
tree[t][i][i-1]=tree[t][i][i+1]=q[l];
}
tree[t][len-1][len]=tree[t][1][0]=0;
add(tree[t][1][2],tree[t][1][2]);
fo(i,1,len)tree[t][i][len]=1;
return;
}
int mid=l+r>>1;
build(ls,l,mid);build(rs,mid+1,r);
tree[t]=tree[ls] * tree[rs];
}
void modify(int t,int l,int r,int x){
if(l==r){
fo(i,1,len-1){
tree[t][i][i]=p[l];
tree[t][i][i-1]=tree[t][i][i+1]=q[l];
}
tree[t][len-1][len]=tree[t][1][0]=0;
add(tree[t][1][2],tree[t][1][2]);
fo(i,1,len)tree[t][i][len]=1;
return;
}
int mid=l+r>>1;
if(x>mid)modify(rs,mid+1,r,x);
else modify(ls,l,mid,x);
tree[t]=tree[ls] * tree[rs];
}
matrix query(int t,int l,int r,int L,int R){
if(L<=l && r<=R)return tree[t];
int mid=l+r>>1;
matrix ret;
if(L<=mid)ret=ret*query(ls,l,mid,L,R);
if(mid<R)ret=ret*query(rs,mid+1,r,L,R);
return ret;
}
int t[N];
inline void gauss(){
fo(i,1,len-1)ans[i]=(mod-T[i][len])%mod,t[i]=i;
fo(i,1,len-1){
int it=i;
for(;!T[t[it]][i] && it<len;++it);
if(it>i)swap(t[it],t[i]);
int ti=t[i];
ll k=power(T[ti][i],mod-2);
fo(j,i,len-1)T[ti][j]=k * T[ti][j] % mod;
ans[ti]=k * ans[ti] % mod;
fo(j,i+1,len-1){
int tj=t[j];
if(!T[tj][i])continue;
k=T[tj][i];
fo(l,i,len-1)dec(T[tj][l] ,k * T[ti][l] % mod);
dec(ans[tj] ,k * ans[ti] % mod);
}
}
fd(i,len-1,2){
fo(j,1,i-1){
int x=t[i],y=t[j];
dec(ans[y] ,(ll)ans[x] * T[y][i] % mod);
}
}
}
inline int read(){
char ch=getchar();
int t=0;
while(ch<'0' || '9'<ch)ch=getchar();
while('0'<=ch && ch<='9'){
t=t*10+ch-'0';
ch=getchar();
}
return t;
}
int main(){
freopen("samsara.in","r",stdin);
freopen("samsara.out","w",stdout);
n=read();m=read();Q=read();
len=m+2;
inv2=power(2,mod-2);
fo(i,1,n){
ll x,y;
x=read();y=read();
p[i]=x * power(y ,mod-2) % mod;
q[i]=(1ll + mod - p[i]) * inv2 % mod;
}
build(1,1,n);
while(Q--){
int type;
type=read();
if(type==1){
int x;
x=read();
if(x==1)T=tree[1];
else T = query(1,1,n,x,n) * query(1,1,n,1,x-1);
fo(i,1,len)--T[i][i];
gauss();
printf("%d
",ans[1]);
}else{
ll x,a,b;
x=read();a=read();b=read();
p[x]=a * power(b ,mod-2) % mod;
q[x]=(1ll + mod - p[x]) * inv2 % mod;
modify(1,1,n,x);
}
}
return 0;
}