• 【loj2552】【CTSC2018】假面


    题目

    (n)个敌方单位,初始生命值分别为(m_1,cdots,m_n) ;

    假面可以释放(Q)个技能:

    $op = 0 , id , u , v $ 表示对(id)号敌人有(frac{u}{v})的概率造成(1)点伤害;

    $op = 1 , k , a_1,cdots a_k $  表示在这些位置中生命值为正的位置里随机选择一个位置释放结界;

    你需要对每个(op=1),输出(a_1,cdots, a_k)中结界的期望((op=1)操作最多(C)次);

    $n le 200 , Q le 200000 , C le 1000 ,m_i le 100 $ ;

    题解

    • Part 1

    • (f_{i,j})表示(i)受到的伤害为(j)的概率,设(x=frac{u}{v}),则(f_{i,j} = x imes f_{i,j-1} + (1-x) imes f_{i,j})

    • (p_i)表示(i)号敌人存活的概率,$p_i = sum_{j=0}^{m_i-1} f_{i,j} $

    • 剩余生命的期望(q_i = sum_{j=0}^{m_i-1}f_{i,j} imes (m_i-j))

    • **Part 2 **

    • 把所有(a_i)拎出来讨论,设存活概率为(p_i) , (g_{i,j})表示不算第(i)个敌人,存活的个数为(j)的概率,(G_j)表示所有人都算上存活个数为(j)的概率,一个人对于(G)的贡献是:

      $G_{j} = p_i imes G_{j-1} + (1-p_i) imes G_{j} $

    • 这个式子是可逆的,即:

      [egin{cases} g_{i,j} &= frac{G_j - p_i imes g_{i,j-1}}{1-p_i} & p_i != 1 \ g_{i,j} &= G_{j+1} & p_i==1 end{cases} ]

    • 时间复杂度:(O(QM + nMC))

      #include<bits/stdc++.h>
      #define vec vector<int>
      #define pb push_back
      #define mod 998244353
      #define ll long long
      using namespace std;
      const int N=810;
      int n,m,a[N],b[N],f[N][N],tot,ny[N],p[N],g[N],t[N];
      char gc(){
      	static char*p1,*p2,s[1000000];
      	if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin);
      	return(p1==p2)?EOF:*p1++;
      }
      int rd(){
      	int x=0;char c=gc();
      	while(c<'0'||c>'9')c=gc();
      	while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-'0',c=gc();
      	return x;
      }
      int pw(int x,int y){
      	int re=1;
      	if(y<0)y+=mod-1;
      	while(y){
      		if(y&1)re=(ll)re*x%mod;
      		y>>=1;x=(ll)x*x%mod;
      	}
      	return re;
      }
      void inc(int&x,int y){x+=y;if(x>=mod)x-=mod;}
      void solve(){
      	for(int i=1;i<=tot;++i)g[i]=0;g[0]=1;
      	for(int i=1;i<=tot;++i){
      		int x=b[i],y=(mod+1-x)%mod;
      		for(int j=tot;~j;--j){
      			g[j]=(ll)g[j]*y%mod;
      			if(j)inc(g[j],(ll)g[j-1]*x%mod);
      		}
      	}
      	for(int j=0;j<=tot;++j)t[j]=g[j];
      	for(int i=1;i<=tot;++i){
      		int re=0,x=b[i],y=pw((mod+1-x)%mod,mod-2);
      		if(x==1){for(int j=0;j<tot;++j)g[j]=g[j+1];g[tot]=0;}
      		else{
      			g[0]=(ll)g[0]*y%mod;
      			for(int j=1;j<=tot;++j)g[j]=(g[j]-(ll)g[j-1]*x%mod+mod)%mod*y%mod;
      		}
      		for(int j=0;j<=tot;++j){
      			inc(re,(ll)ny[j+1]*b[i]%mod*g[j]%mod);
      			g[j]=t[j];
      		}
      		printf("%d ",re);
      	}
      	puts("");
      }
      int main(){
      //	freopen("faceless.in","r",stdin);
      //	freopen("faceless.out","w",stdout);
      	n=rd();
      	for(int i=1;i<=n;++i)a[i]=rd(),f[i][0]=p[i]=1;
      	ny[1]=1;for(int i=2;i<=n<<2;++i)ny[i]=1ll*(mod-mod/i)*ny[mod%i]%mod;
      	m=rd();
      	for(int i=1;i<=m;++i){
      		int op,id,x,y;
      		op=rd();
      		if(!op){
      			id=rd();x=rd();y=rd();
      			x=(ll)x*pw(y,mod-2)%mod;
      			y=(mod+1-x)%mod;p[id]=0;
      			for(int j=a[id]-1;~j;--j){
      				f[id][j]=(ll)f[id][j]*y%mod;
      				if(j)inc(f[id][j],(ll)f[id][j-1]*x%mod);
      				inc(p[id],f[id][j]);
      			}
      		}else {
      			tot=rd();
      			for(int j=1;j<=tot;++j)b[j]=p[rd()];
      			solve();
      		}
      	}
      	for(int i=1;i<=n;++i){
      		int x=0;
      		for(int j=0;j<a[i];++j)inc(x,(ll)(a[i]-j)*f[i][j]%mod);
      		printf("%d ",x);
      	}
      	return 0;
      }
      
  • 相关阅读:
    当Table中td内容为空时,让它显示边框的办法
    超链接可以是JS代码
    学习Filter
    关于SQL语句的拼接问题
    复习JSP时遇到的几个问题
    凡是项目中的增删改都要加事务
    Xshell和SecureCRT连不上VMware虚拟机linux系统
    IBM AIX定义数组变量
    Python模块之re 正则表达式
    Python模块之itertools 用于创建和使用迭代器的函数工具
  • 原文地址:https://www.cnblogs.com/Paul-Guderian/p/10825318.html
Copyright © 2020-2023  润新知