• 并不对劲的bzoj5340:loj2552:uoj399:p4564: [Ctsc2018]假面


    题目大意

    (n)((nleq200))个非负整数(m_1,m_2,...,m_n)((forall iin[1,n],m_ileq100)),有(q)((qleq2*10^5))个操作,每个操作是以下两种之一:
    (1)给出位置(x),概率(q),若(m_x)大于0,则有(q)的概率将(m_x)减一;若(m_x)为0,则不进行任何操作
    (2)给出一个数(k)(k)个不重复的位置(d_1,d_2,...d_k),在(m_{d_1},...,m_{d_k})中随机选一个正数,求选中位置(d_1,...,d_k)的概率各是多少,这种操作不超过1000个
    最后输出每个位置上的数在经过(q)个操作后期望分别是多少。

    题解

    (p_{i,j})表示现在第(i)个数还剩(j)的概率是多少
    在进行操作前,(p_{i,m_i}=1),其他的(p_{i,j})都为0
    如果是操作(1),(x)(q)的概率减一,也就是说,(p_{x,j})(q)的概率转移到(p_{x,j-1})(p_{x,j})(1-q)的概率转移到(p_{x,j}),特殊地,(p_{x,0})(1)的概率转移到(p_{x,0})
    如果是操作(2),设(g_{i,j})表示在不考虑(d_i)时,有(j)个数是正数的概率,那么(d_i)是正数且被选中的概率就是$$(1-p_{d_i,0})(sum_{j=0}^{k-1}g_{i,j}frac{1}{k+1})$$这样,在已知(g)的情况下,就可以在(Theta(k^2))的时间内求出一次(2)操作的答案了
    那么(g)该怎么求呢?设(f_{i,j})表示考虑位置(d_1,...,d_i)位置上的数,其中正数有(j)
    初始(f_{0,0}=1),转移为$$ f_{i,j} egin{cases} f_{i-1,j-1}(1-p_{d_i,0})+f_{i-1,j}p_{d_i,0} & ext {j>0} f_{i-1,j}*p_{d_i,0} & ext{j=0} end{cases} $$
    这样就能求出在这(k)个位置中,有(j)个位置上的数是正数的概率了,但是该如何把这个某个位置上的数的影响去掉,求出(g)呢?
    重新dp一遍想必是不可能的,那样对于每个(d_i)都要重新进行(Theta(k^2))的dp,一次(2)操作就是(Theta(k^3)),时间超限了
    能否用(f)(p)进行一些变化求出(p)呢?会发现在已知(f_{i+1,0},...,f_{i+1,k})(p_{d_{i+1},0})时,是可以求出(f_{i,0},...,f_{i,k})
    先把推出(f_{i+1,0},...,f_{i+1,k})的所有式子写出来:
    (f_{i+1,0}= f_{i,0}*p_{d_{i+1},0})
    (f_{i+1,1}= f_{i,0}*(1-p_{d_{i+1},0})+f_{i,1}*p_{d_{i+1},0})
    (...)
    (f_{i+1,k}= f_{i,k-1}*(1-p_{d_{i+1},0})+f_{i,k}*p_{d_{i+1},0})
    再把(f_{i,0},...,f_{i,k})拿到左边:
    (f_{i,0}= frac{f_{i+1,0}}{p_{d_{i+1},0}})
    (f_{i,1}= frac{f_{i+1,1}-f_{i,0}*(1-p_{d_{i+1},0})}{p_{d_{i+1},0}})
    (...)
    (f_{i,k}= frac{f_{i+1,k}-f_{i,k-1}*(1-p_{d_{i+1},0})}{p_{d_{i+1},0}})
    特殊地,当(p_{d_{i+1},0}=0)时,(f_{i,j}=f_{i+1,j+1})
    这个变化的复杂度是(Theta(k))
    (f_{i+1,...})本来是(d_1,..,d_{i+1})的答案,经过变化后,(f_{i,...})(d_1,..,d_{i})的答案,这相当于把(d_{i+1})位置上的数的影响从(f_{i+1,...})中去掉
    那么(g_{i,...})可以看成把(d_i)位置上的数的影响从(f_{n,...})中删去,就可以进行相似的变化
    (p_{d_{i+1},0} eq 0)时,
    (g_{i,0}= frac{f_{n,0}}{p_{d_{i+1},0}})
    (g_{i,1}= frac{f_{n,1}-g_{i,0}*(1-p_{d_{i+1},0})}{p_{d_{i+1},0}})
    (...)
    (g_{i,k}= frac{f_{n,k}-g_{i,k-1}*(1-p_{d_{i+1},0})}{p_{d_{i+1},0}})
    (p_{d_{i+1},0}=0)时,(g_{i,j}=f_{g,j+1})

    代码
    #include<algorithm>
    #include<cmath>
    #include<complex>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<ctime>
    #include<iomanip>
    #include<iostream>
    #include<map>
    #include<queue>
    #include<set>
    #include<stack>
    #include<vector>
    #define rep(i,x,y) for(register int i=(x);i<=(y);++i)
    #define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
    #define maxn 210 
    #define maxm 110
    #define LL long long
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)&&ch!='-')ch=getchar();
    	if(ch=='-')f=-1,ch=getchar();
    	while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    	return x*f;
    }
    void write(int x)
    {
    	if(x==0){putchar('0');return;}
    	int f=0;char ch[20];
    	if(x<0)putchar('-'),x=-x;
    	while(x)ch[++f]=x%10+'0',x/=10;
    	while(f)putchar(ch[f--]);
    	return;
    }
    const LL mod=998244353;
    int inv[maxn],n,q,m[maxn],p[maxn][maxm],f[2][maxn],g[maxn],id[maxn],yes[maxn],no[maxn],num;
    int qp(int x,int y){int ans=1;while(y){if(y&1)ans=(LL)ans*(LL)x%mod;x=(LL)x*(LL)x%mod,y>>=1;}return ans;}
    void work()
    {
    	rep(i,1,num)f[0][i]=0;f[0][0]=1;
    	rep(i,0,num-1)
    	{
    		int now=i&1,nxt=now^1;
    		rep(j,0,i)
    		{
    			f[nxt][j+1]=((LL)f[nxt][j+1]+(LL)f[now][j]*(LL)yes[i+1]%mod)%mod;
    			f[nxt][j]=((LL)f[nxt][j]+(LL)f[now][j]*(LL)no[i+1]%mod)%mod;
    			f[now][j]=0;
    		}
    	}
    	rep(i,1,num)
    	{
    		int res=0,fdie=qp(no[i],mod-2); 
    		if(no[i]!=0)
    		{
    			g[0]=(LL)f[num&1][0]*(LL)fdie%mod; 
    			rep(j,1,num-1)g[j]=(f[num&1][j]-(LL)g[j-1]*(LL)yes[i]%mod+mod)%mod*(LL)fdie%mod;
    		}
    		else
    		{
    			rep(j,0,num-1)g[j]=f[num&1][j+1];
    		}
    		rep(j,0,num-1)res=(res+(LL)yes[i]*(LL)g[j]%mod*(LL)inv[j+1]%mod)%mod;
    		write(res);
    		if(i!=num)putchar(' '); 
    	}
    	rep(i,0,num)f[num&1][i]=0;
    	putchar('
    ');
    }
    int main()
    {
    	n=read();
    	rep(i,1,n)m[i]=read(),p[i][m[i]]=1,inv[i]=qp(i,mod-2);
    	q=read();
    	while(q--)
    	{
    		int op=read();
    		if(op)
    		{
    			num=read();
    			rep(i,1,num)id[i]=read();
    			rep(i,1,num)no[i]=p[id[i]][0],yes[i]=(1-p[id[i]][0]+mod)%mod;
    			work();
    		}
    		else
    		{
    			int x=read(),u=read(),v=read(),die=(LL)u*(LL)qp(v,mod-2)%mod,live=(LL)(v-u)%mod*(LL)qp(v,mod-2)%mod;
    			rep(i,1,m[x])p[x][i-1]=(p[x][i-1]+(LL)p[x][i]*(LL)die%mod)%mod,p[x][i]=(LL)p[x][i]*(LL)live%mod;
    		}
    	}
    	rep(i,1,n)
    	{
    		int res=0;
    		rep(j,1,m[i])res=(res+(LL)j*(LL)p[i][j]%mod)%mod;
    		write(res);
    		if(i!=n)putchar(' ');
    	}
    	return 0;
    }
    
    
    一些意见

    第一次见需要对dp结果去掉一个决策的影响的题
    以及今天学会设置友链了!

  • 相关阅读:
    服务器搭建纪录linux+mysql+nginx+php
    win7 64下安装mysql-python报错的解决办法
    jQuery treeview的简单用法
    不测的秘密:精准测试之路----读书笔记(第一章)
    [摘]ASP.Net标准控件(TextBox控件)
    让两个Div并排显示
    ScrollView里面添加ListView时,解决ListView的显示问题
    注册信息时,验证码的发送与验证
    头像图片上传到sd及服务器
    把图片转换成圆形图片
  • 原文地址:https://www.cnblogs.com/xzyf/p/10037375.html
Copyright © 2020-2023  润新知