zoukankan      html  css  js  c++  java
  • Solution -「APIO 2016」「洛谷 P3643」划艇

    (mathcal{Description})

      Link & 双倍经验.

      给定 (n) 个区间 ([a_i,b_i))注意原题是闭区间,这里只为方便后文描述),求 ({c_n}) 的个数,使得:

    • (forall i~~~~c_i=0lor c_iin[a_i,b_i))
    • (forall i<j~~~~c_i ot=0land c_j ot=0Rightarrow c_i<c_j)

      对 (10^9+7) 取模。

      (nle500)(1le a_ile b_ile10^9)

    (mathcal{Solution})

      一个很 naive 的 DP 想法,(f(i,j)) 表示考虑前 (i) 个位置,(c_i=j~(j ot=0)) 时的方案数。问题在于第二维开销过大,考虑离散化所有端点坐标。

      先来一个引理,取值在 ([a,b)),长度为 (n) 的上升整数序列的个数为 (inom{b-a}{n}),显然选 (n) 个数就可以了。

      再来一个引理,取值在 ([a,b)cup{0}),长度为 (n),非零的位置是上升整数序列的序列个数为 (inom{b-a+n}{n}),证明也很显然,有几个 (0) 可以选,虽然不同的 (0) 可以任意排列,但看上去都是一样的。所以钦定 (0) 的大小关系后就等价于令区间为 ([a-n,b]),长度为 (n) 时的上一引理。

      接着刚才的思路,离散化时,排过序的端点们把坐标轴分为若左闭右开的区间,从左开始第 (t) 个区间称作第 (t) 段。令 (f(i,j)) 表示考虑前 (i) 个位置,(c_i) 属于(j)时的方案数。设 ([j,j+1)) 实际映射 ([a,b)),枚举 (k<i),转移:

    [f(i,j)leftarrow f(i,j)+f(k,j-1)inom{b-a+x-1}{x},~~~~ ext{where }x=1+sum_{t=k+1}^{j-1}[jin[a_t,b_t)] ]

      组合数运用了引理二。注意钦定 (c_i) 不为 (0),所以上面 (-1)

      扫 (f) 就结束了,交换枚举顺序,第二维还可以滚掉。复杂度 (mathcal O(n^3))

    (mathcal{Code})

    /* Clearink */
    
    #include <cstdio>
    #include <algorithm>
    
    const int MAXN = 500, MOD = 1e9 + 7;
    int n, a[MAXN + 5], b[MAXN + 5], tmp[MAXN * 2 + 5], inv[MAXN + 5];
    int f[MAXN + 5], comb[MAXN + 5];
    
    inline int mul ( long long a, const int b ) { return a * b % MOD; }
    inline int& addeq ( int& a, const int b ) { return ( a += b ) < MOD ? a : a -= MOD; }
    
    int main () {
    	scanf ( "%d", &n ), inv[1] = 1;
    	for ( int i = 1; i <= n; ++ i ) {
    		if ( i > 1 ) inv[i] = mul ( MOD - MOD / i, inv[MOD % i] );
    		scanf ( "%d %d", &a[i], &b[i] ), ++ b[i];
    		tmp[2 * i - 1] = a[i], tmp[i << 1] = b[i];
    	}
    	std::sort ( tmp + 1, tmp + ( n << 1 | 1 ) );
    	int m = std::unique ( tmp + 1, tmp + ( n << 1 | 1 ) ) - tmp - 1;
    	for ( int i = 1; i <= n; ++ i ) {
    		a[i] = std::lower_bound ( tmp + 1, tmp + m + 1, a[i] ) - tmp;
    		b[i] = std::lower_bound ( tmp + 1, tmp + m + 1, b[i] ) - tmp;
    	}
    	f[0] = 1;
    	for ( int j = 1, len; j < m; ++ j ) {
    		len = tmp[j + 1] - tmp[j], comb[0] = 1;
    		for ( int i = 1; i <= n; ++ i ) {
    			comb[i] = mul ( mul ( comb[i - 1], len + i - 1 ), inv[i] );
    		}
    		for ( int i = n; i; -- i ) {
    			if ( j < a[i] || b[i] <= j ) continue;
    			for ( int k = i - 1, c = 1; ~k; -- k ) {
    				addeq ( f[i], mul ( comb[c], f[k] ) );
    				if ( a[k] <= j && j < b[k] ) ++ c;
    			}
    		}
    	}
    	int ans = 0;
    	for ( int i = 1; i <= n; ++ i ) addeq ( ans, f[i] );
    	printf ( "%d
    ", ans );
    	return 0;
    }
    

    (mathcal{Details})

      目前洛谷最优解,兔的代码吸口氧真的快到飞起 www。

  • 相关阅读:
    第一阶段——站立会议总结DAY10
    第十二周学习进度条
    第一阶段——站立会议总结DAY09
    第一阶段——站立会议总结DAY08
    人机交互设计课下作业
    第一阶段——站立会议总结DAY07
    第一阶段——站立会议总结DAY06
    第一阶段——站立会议总结DAY05
    个人总结
    第二个冲刺期的第十天
  • 原文地址:https://www.cnblogs.com/rainybunny/p/13823342.html
Copyright © 2011-2022 走看看