zoukankan      html  css  js  c++  java
  • 【题解】担心

    区间DP + 组合计数

    (f(i, j))为只考虑([i, j])段,且(i,j)能够相遇的概率。

    特别地,设(f(0, i))(i)能打败左边所有人的概率,(f(i, n+1))(i)能打败右边所有人的概率。

    转移只需要枚举中间点(k),考虑最后剩下三个人((i, k, j)),有一半概率抽到((i, k)),一半概率抽到((k, j)),计算概率即可。a

    关键在于在到达最终状态((i, k, j))之前,要保证((i, k))((k, j))不能被选中对决,因此要计算概率并乘上去。

    (k-i+1=n, j-k+1=m),则能达到最终状态的概率为:

    [dfrac{(n-1)!(m-1)! inom{n+m-4}{n-2}}{dfrac{(n+m-2)!}{2}} ]

    其中((n-1)!)(n-1)(n-2)的排列

    (dfrac{(n+m-2)!}{2})((n+m-2))(n+m-4)的排列(总方案数)

    即先内部排列,最后再整体可重排列。

    对于(f(0, i))(f(i, n+1))类似。

    Code

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    
    #define File(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
    
    const int p = 998244353, N = 505, inv2 = 499122177;
    inline int add(int x, int y){return x+y>=p ? x+y-p : x+y;}
    inline int sub(int x, int y){return x-y<0 ? x-y+p :x-y;}
    inline int mul(int x, int y){return 1LL * x * y % p;}
    inline int power(int x, int y){
    	int res = 1;
    	for(; y; y>>=1, x = mul(x, x)) if(y & 1) res = mul(res, x);
    	return res;
    }
    
    int fac[N], ifac[N];
    void preBinom(int n){
    	fac[0] = fac[1] = 1;
    	for(int i=2; i<=n; i++) fac[i] = mul(fac[i-1], i);
    	ifac[n] = power(fac[n], p - 2);
    	for(int i=n-1; i>=0; i--) ifac[i] = mul(ifac[i+1], i+1);
    }
    int C(int n, int m){return mul(fac[n], mul(ifac[m], ifac[n-m]));}
    int F(int n, int m){ // 左右两边分别为n,m个元素
    	return mul(mul(mul(fac[n-1], fac[m-1]), C(n+m-4, n-2)), mul(ifac[n+m-2], 2));
    }
    
    int a[N];
    int Pr[N][N], f[N][N];
    
    int main(){
    	int n, pos;
    	scanf("%d%d", &n, &pos);
    	preBinom(n+3);
    	for(int i=1; i<=n; i++) scanf("%d", a + i), f[i-1][i] = 1;
    	f[n][n+1] = 1;
    	for(int i=1; i<=n; i++)
    		for(int j=i+1; j<=n; j++){
    			Pr[i][j] = mul(a[i] % p, power((a[i] + a[j]) % p, p - 2));
    			Pr[j][i] = sub(1, Pr[i][j]);
    		}
    	for(int len=2; len<=n; len++){
    		for(int i=1; i<len; i++) f[0][len] = add(f[0][len],	
    			mul(
    				mul(mul(f[0][i], f[i][len]), Pr[len][i]),
    				mul(mul(mul(fac[i-1], fac[len-i]), C(len-2, i-1)), ifac[len-1])
    			)
    		);
    		int now = n + 1 - len;
    		for(int i=n+2-len; i<=n; i++){
    			f[n+1-len][n+1] = add(f[n+1-len][n+1],
    				mul(
    					mul(mul(f[n+1-len][i], f[i][n+1]), Pr[n+1-len][i]),
    					mul(mul(mul(fac[i-now], fac[n-i]), C(n-1-now, i-now-1)), ifac[n-now])
    				)
    			);
    		}
    		for(int i=1; i+len<=n; i++){
    			int j = i + len;
    			for(int k=i+1; k<j; k++)
    				f[i][j] = add(f[i][j],
    					mul(mul(
    						mul(inv2, add(Pr[i][k], Pr[j][k])),
    						mul(f[i][k], f[k][j])),
    						F(k-i+1, j-k+1)
    					)
    				);
    		}
    	}
    	printf("%d
    ", mul(f[0][pos], f[pos][n+1]));
    	return 0;
    }
    
  • 相关阅读:
    模板方法模式
    备忘录模式
    观察者模式
    中介者模式
    迭代器模式
    Char型和string型字符串比较整理
    命令模式
    责任链模式
    代理模式
    dokcer 杂谈
  • 原文地址:https://www.cnblogs.com/RiverHamster/p/sol-oj4043.html
Copyright © 2011-2022 走看看