2021.08.16【2022省赛模拟】轮回

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\) 需要线段树维护,复杂度 $ O(n \log n K^3) $​ 。

解法二

同样写出转移矩阵,同样要求出 \(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;
}
posted @ 2021-08-19 21:08  Kelvin2005  阅读(36)  评论(0编辑  收藏  举报