zoukankan      html  css  js  c++  java
  • Solution -「CF 494C」Helping People

    (mathcal{Description})

      Link.

      给定序列 ({a_n})(m) 个操作,第 (i) 个操作有 (p_i) 的概率将 ([l_i,r_i]) 内的元素 (+1)。且保证任意两个区间要么不交,要么有包含关系。求所有操作完成后序列最大值的期望。

      (nle10^5)(mle5000)

    (mathcal{Solution})

      首先应当知道,(E(max{a_i}) ot=max{E(a_i)})(不然还需要做嘛 qwq),这是由于每个数的期望值是不独立的。

      从题目奇怪的限制入手——各区间构成树形关系,整个序列上的区间构成一片森林。不妨加入第 (m+1) 个操作区间,满足 (l_{m+1}=1,r_{m+1}=n,p_{m+1}=0),区间就构成一棵严格的树了。

      考虑树上 DP,令 (f(u,i)) 表示操作完 (u) 子树内的所有操作后,区间最大值 (le i) 的概率。同时注意到 (m) 相较于值域大小 (10^9) 非常小,所以很多数是不可能成为最大值的。记 (u) 子树所代表的区间内初始元素的最大值 (mx_u),不难发现仅有 (kin[mx_u,mx_u+m])(f(u,k)) 有意义,而其余 (f(u,k)) 要不为 (0) 要不为 (1),没有记录的必要。那么状态就能优化为操作完 (u) 子树内的所有操作后,区间最大值 (le i+mx_u) 的概率,并保证 (iin[0,m])。转移就简单了:

    [f(u,i)=p_iprod_vf(v,mx_u-mx_v+i-1)+(1-p_i)prod_vf(v,mx_u-mx_v+i) ]

      注意单独计算 (f(u,0)),因为其前一项应取 (0)

      复杂度 (mathcal O(nlog n+m^2))。(前一项为预处理 ST 表复杂度。)

    (mathcal{Code})

    #include <cstdio>
    #include <vector>
    #include <algorithm>
    
    const int MAXN = 1e5, MAXLG = 16, MAXM = 5000;
    int n, m, mxa, a[MAXN + 5], lg[MAXN + 5], st[MAXN + 5][MAXLG + 5];
    std::vector<int> tree[MAXM + 5];
    double f[MAXM + 5][MAXM + 5];
    
    inline void chkmax ( int& a, const int b ) { if ( a < b ) a = b; }
    
    inline int min_ ( const int a, const int b ) { return a < b ? a : b; }
    
    inline int rint () {
    	int x = 0; char s = getchar ();
    	for ( ; s < '0' || '9' < s; s = getchar () );
    	for ( ; '0' <= s && s <= '9'; s = getchar () ) x = x * 10 + ( s ^ '0' );
    	return x;
    }
    
    inline int qmax ( const int l, const int r ) {
    	int k = lg[r - l + 1], ret = st[l][k];
    	return chkmax ( ret, st[r - ( 1 << k ) + 1][k] ), ret;
    }
    
    struct Section {
    	int l, r, mx; double p;
    	inline void read () {
    		l = rint (), r = rint (), mx = qmax ( l, r );
    		scanf ( "%lf", &p );
    	}
    	inline bool operator < ( const Section t ) const {
    		return l ^ t.l ? l < t.l : r > t.r;
    	}
    } sec[MAXM + 5];
    
    inline void solve ( const int u ) {
    	for ( int v: tree[u] ) solve ( v );
    	f[u][0] = 1 - sec[u].p;
    	for ( int v: tree[u] ) f[u][0] *= f[v][sec[u].mx - sec[v].mx];
    	for ( int i = 1; i <= m; ++ i ) {
    		double p = 1, q = 1;
    		for ( int v: tree[u] ) {
    			p *= f[v][min_ ( sec[u].mx + i - sec[v].mx - 1, m )];
    			q *= f[v][min_ ( sec[u].mx + i - sec[v].mx, m )];
    		}
    		f[u][i] = sec[u].p * p + ( 1 - sec[u].p ) * q;
    	}
    }
    
    int main () {
    	n = rint (), m = rint ();
    	for ( int i = 1; i <= n; ++ i ) chkmax ( mxa, a[i] = st[i][0] = rint () );
    	for ( int i = 2; i <= n; ++ i ) lg[i] = lg[i >> 1] + 1;
    	for ( int j = 1; 1 << j <= n; ++ j ) {
    		for ( int i = 1; i + ( 1 << j ) - 1 <= n; ++ i ) {
    			chkmax ( st[i][j] = st[i][j - 1], st[i + ( 1 << j >> 1 )][j - 1] );
    		}
    	}
    	for ( int i = 1; i <= m; ++ i ) sec[i].read ();
    	sec[++ m] = { 1, n, qmax ( 1, n ), 0.0 };
    	std::sort ( sec + 1, sec + m + 1 );
    	for ( int i = 2; i <= m; ++ i ) {
    		for ( int j = i - 1; j; -- j ) {
    			if ( sec[j].l <= sec[i].l && sec[i].r <= sec[j].r ) {
    				tree[j].push_back ( i );
    				break;
    			}
    		}
    	}
    	solve ( 1 );
    	double ans = 0;
    	for ( int i = 0; i <= m; ++ i ) {
    		ans += ( i + mxa ) * ( f[1][i] - f[1][i - 1] );
    	}
    	printf ( "%.12f
    ", ans );
    	return 0;
    }
    
  • 相关阅读:
    学号20155308 2016-2017-2 《Java程序设计》第6周学习总结
    学号20155308 2016-2017-2 《Java程序设计》第5周学习总结
    # 学号20155308 2006-2007-2 《Java程序设计》第4周学习总结
    学号20155308 2006-2007-2 《Java程序设计》第3周学习总结
    第二周作业--20155308郝文菲
    20155308郝文菲
    20155308郝文菲--第三次作业
    郝文菲get技能的经验--20155308
    第一篇博客
    20155302杨效宸第三次随笔
  • 原文地址:https://www.cnblogs.com/rainybunny/p/13481260.html
Copyright © 2011-2022 走看看