2021.08.16【2022省賽模擬】輪迴
阿新 • • 發佈:2021-08-19
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 \times \prod_{i=1}^{S-1}P$ ,即轉一圈的轉移矩陣,那麼這一時刻的概率就是一個無窮級數求和的形式,套用公式 \(\frac1{1-X}\)
解法二
同樣寫出轉移矩陣,同樣要求出 \(A\) ,同樣線段樹維護,設 \(F_i\) 為時刻為 \(i\) 處的期望步數(是個行向量),那麼有 \(F_iA = F_i\) ,高斯消元解出即可,複雜度同樣 \(O(n \log n K^3)\)
Hint
複雜度不太對勁。。。然而我們發現轉移矩陣可以從 \((2K+1) \times (2K+1)\) 壓縮成 $ (K+1) \times (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\n",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; }