• 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 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;
    }
    
  • 相关阅读:
    优雅解决Windows版Emacs的home路径的问题
    不容忽视的警告:默认库msvcrt.lib与其他库的使用冲突,请使用/NODEFAULTLIB:library
    搜狗浏览器也可以直接安装Chrome插件,太棒了
    给phpMyAdmin修改root密码后出现访问被拒绝的问题的解决办法
    给Eclipse替换镜像
    centos7 添加系统盘作为本地yum源
    python的学习内容
    列表
    Oracle-创建用户和表空间
    linux下oracle的启动和停止
  • 原文地址:https://www.cnblogs.com/Kelvin2005/p/15163865.html
Copyright © 2020-2023  润新知