zoukankan      html  css  js  c++  java
  • 洛谷p3643[APIO2016]划艇

    【洛谷p3643】[APIO2016]划艇

    题面

    洛谷

    题解

    组合(dp)
    我们设(f[i][j])表示第(i)所学校参赛,并且派出了(j)艘划艇的方案数。
    不难得到:

    [f_{0,1} = 1 ]

    [f_{i,j} = j∈I_i ? sum_{k=1}^{j-1}sum_{p=0}^{i-1}f_{p,k}:0 ]

    答案即为(f_{i,j})之和。
    这时我们发现(1)个问题,那就是第二维的复杂度是(10^9)的,并不能承受。
    于是我们考虑离散化。
    离散化之后设(f_{i,j})表示第(i)所学校参赛并且派出的划艇数在(j)这个区间里的方案数。
    此时需要知道一点,
    那就是从区间([0,l])中取(n)个数,使得所有非(0)数严格递增,方案数为(inom{l+n}{n})
    我们枚举前(p)所学校不在区间(j)中,则(M)(p+1 sim i)号学校中能选区间(j)学校的数量。

    [f_{i,j}=sum_{k=1}^{j-1} sum_{p=0}^{i-1}inom{l+M-1}{M}f_{p,k} ]

    此时可以前缀和优化,这题就做完了。

    代码

    #include <bits/stdc++.h>
    
    const int maxn = 510;
    const int mod = 1e9 + 7;
    typedef long long ll;
    using std::sort;
    
    int n, m, i, j, k, N;                            
    int l[maxn], r[maxn], a[maxn << 1];             
    int inv[maxn], c[maxn], f[maxn];
    
    inline void get_inv(int n) {
    	inv[1] = 1;    
    	for(int i = 2;i <= n;i++)
    		inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod;     
    	return;
    }
    inline int add(ll a,ll b) {
    	ll c = a + b;
    	return c >= mod ? c - mod : c;    
    }
    
    int main() {
    	scanf("%d",&N);  
    	get_inv(N);   
    	for(int i = 1;i <= N;i++)
    		scanf("%d %d",l + i,r + i), a[++n] = l[i], a[++n] = r[i] + 1;
    	sort(a + 1,a + n + 1);
    	n = std::unique(a + 1,a + n + 1) - a - 1;
    	for(int i = 1;i <= N;i++)
    		l[i] = std::lower_bound(a + 1,a + n + 1,l[i]) - a,
    		r[i] = std::lower_bound(a + 1,a + n + 1,r[i] + 1) - a;
    	c[0] = f[0] = 1;
    	for(int j = 1;j < n;j++) {
    		int le = a[j + 1] - a[j];
    		for(int i = 1;i <= N;i++)
    			c[i] = 1ll * c[i - 1] * (le + i - 1) % mod * inv[i] % mod;
    		for(int i = N;i >= 1;i--) {
    			if(l[i] <= j && j + 1 <= r[i]) {
    				int o = 0, p = 1, t = le;
    				for(int k = i - 1;~k;k--) {
    					o = add(1ll * o,1ll * t * f[k] % mod);
    					if(l[k] <= j && j + 1 <= r[k])
    						t = c[++p];   
    				}
    				f[i] = add(f[i],o);  
    			}
    		}
    	}
    	int ans = 0;
    	for(int i = 1;i <= N;i++)
    		ans = add(ans,f[i]);
    	printf("%d
    ",ans);
    	return 0;      
    }
    
    
  • 相关阅读:
    2018.11.12
    2018.11.8
    2018.11.7
    2018.11.6
    2018.11.5
    学习python课程第七天
    作业四.
    学习python课程第六天
    作业3
    学习python课程第五天
  • 原文地址:https://www.cnblogs.com/Sai0511/p/11310350.html
Copyright © 2011-2022 走看看