zoukankan      html  css  js  c++  java
  • Solution -「ARC 104E」Random LIS

    (mathcal{Description})

      Link.

      给定整数序列 ({a_n}),对于整数序列 ({b_n})(b_i)([1,a_i]) 中等概率随机。求 ({b_n}) 中 LIS(最长上升子序列)的期望长度。对 (10^9+7) 取模。

      (nle6)(a_ile10^9)

    (mathcal{Solution})

      欺负这个 (n) 小得可爱,直接 (mathcal O(n!)) 枚举 ((b_i,i)) 的二维偏序关系,记排列 ({p_n})(p_i) 表示第 (i) 小的二元组是 ((b_{p_i},p_i))。于是乎,({b_n}) 就会满足:

    [b_{p_1}le b_{p_2}le cdots le b_{p_n} ]

      但其中有些地方是不能取等的。可以发现若 (p_i<p_{i+1}),则必须取 (b_{p_i}<b_{p_{i+1}})。考虑把所有如此的小于全部变成小于等于:将所有 (j>i)(b_{p_j}leftarrow b_{p_j}-1) 即可。

      为方便进一步思考,把 ({a_n})({b_n})({p_n}) 的位置排列。问题变成:求不降序列 ({b_n}) 的个数,满足 (b_iin[1,a_i])

      法一,「APIO 2016」划艇。尝试另一种方法——问题可转化为从 ((1,1)) 走到 ((n+1,+infty)),只能向上或向右走,且横坐标为 (x) 时纵坐标不超过 (a_x),求方案数。令 (f(i)) 表示走到 (x=i) 时的合法方案数。转移时计算总方案减不合法方案。钦定不合法方案的第一个不合法位置为 (x=j),方案数即为 (f(j)inom{(a_i-a_j)+(i-j)-1}{i-j})(先走到 ((j,a_j+1)) 保证不合法,再随便走)。所以转移:

    [f(i)=inom{a_i+i-1}{i-1}-sum_{j=1}^{i-1}f(j)inom{a_i-a_j+i-j-1}{i-j} ]

      求组合数 (inom{a}{b})(mathcal O(b)) 暴力求就行,因为 (b)(mathcal O(n)) 的。两种方法的总复杂度均为 (mathcal O(n!n^3))

    (mathcal{Code})

    /* Clearink */
    
    #include <cstdio>
    #include <algorithm>
    
    const int MAXN = 6, MOD = 1e9 + 7;
    const int inv[] = { 0, 1, 500000004, 333333336, 250000002, 400000003, 166666668 };
    int n, a[MAXN + 5], h[MAXN + 5], p[MAXN + 5], f[MAXN + 5];
    
    inline void chkmax ( int& a, const int b ) { a < b ? a = b : 0; }
    inline void chkmin ( int& a, const int b ) { b < a ? a = b : 0; }
    inline void subeq ( int& a, const int b ) { ( a -= b ) < 0 ? a += MOD : 0; }
    inline void addeq ( int& a, const int b ) { ( a += b ) < MOD ? 0 : a -= MOD; }
    
    inline int calcLIS () {
    	int f[MAXN + 5] {}, ret = 0;
    	for ( int i = 1; i <= n; ++ i ) {
    		for ( int j = i - 1; ~j; -- j ) {
    			if ( p[i] > p[j] ) {
    				chkmax ( f[i], f[j] + 1 );
    			}
    		}
    		chkmax ( ret, f[i] );
    	}
    	return ret;
    }
    
    inline int qkpow ( int a, int b, const int p = MOD ) {
    	int ret = 1;
    	for ( ; b; a = 1ll * a * a % p, b >>= 1 ) ret = ret * ( b & 1 ? a : 1ll ) % MOD;
    	return ret;
    }
    
    inline int comb ( const int n, const int m ) {
    	int ret = 1;
    	for ( int i = 1; i <= m; ++ i ) ret = ( n - i + 1ll ) * ret % MOD * inv[i] % MOD;
    	return ret;
    }
    
    int main () {
    	scanf ( "%d", &n );
    	for ( int i = 1; i <= n; ++ i ) scanf ( "%d", &a[p[i] = i] );
    	int ans = 0;
    	do {
    		int lis = calcLIS ();
    		for ( int i = 1; i <= n; ++ i ) h[i] = a[p[i]] - 1;
    		for ( int i = 1; i < n; ++ i ) {
    			if ( p[i] > p[i + 1] ) continue;
    			for ( int j = i + 1; j <= n; ++ j ) -- h[j];
    		}
    		for ( int i = n - 1; i; -- i ) chkmin ( h[i], h[i + 1] );
    		int all = comb ( h[n] + n, n );
    		for ( int i = 1; i <= n; ++ i ) {
    			f[i] = comb ( h[i] + i - 1, i - 1 );
    			for ( int j = 1; j < i; ++ j ) {
    				subeq ( f[i], 1ll * f[j] * comb ( h[i] - h[j] + ( i - j - 1 ), i - j ) % MOD );
    			}
    			subeq ( all, 1ll * f[i] * comb ( h[n] - h[i] + n - i, n - i + 1 ) % MOD );
    		}
    		addeq ( ans, 1ll * all * lis % MOD );
    	} while ( std::next_permutation ( p + 1, p + n + 1 ) );
    	int s = 1;
    	for ( int i = 1; i <= n; ++ i ) s = 1ll * s * a[i] % MOD;
    	printf ( "%d
    ", int ( 1ll * ans * qkpow ( s, MOD - 2 ) % MOD ) );
    	return 0;
    }
    
  • 相关阅读:
    Discuz!X3.2 uc_server密码正确无法登录的解决方法
    手动添加uc应用及其 提示notelist表缺少appX字段的处理方法
    discuz 3 头像显示不成功
    用户名称修改的完美解决方法
    WEB服务器、应用程序服务器、HTTP服务器区别
    小议函数指针
    Difference Between objectForKey and valueForKey in NSDictionary
    valueforkey objectforkey区别,
    budle identifier,
    return,hiding 之前,
  • 原文地址:https://www.cnblogs.com/rainybunny/p/13823545.html
Copyright © 2011-2022 走看看