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

    https://www.luogu.org/problemnew/show/P3643

    题解

    我们发现这道题的值域很大,所以考虑把所有区间端点离散化。

    然后我们就设一个(dp[i][j])表示前i个学校,第i个学校强制选,第i个学校选在了j这个区间的方案数。

    转移我们可以枚举第一个选在j这个区间的学校k。

    [dp[i][j]=blabla*sum_{x=1}^{i-1}sum_{y=1}^{j-1}dp[x][y] ]

    考虑前面的东西怎么算。

    如果每个数都可以选或者不选的话,那么答案就是(inom{n+len}{n})

    现在我们强制头尾必须选。

    我们原来是这样的表达式:

    [C_{num}^0C_{len}^0+C_{num}^1C_{len}^1+C_{num}^2C_{len}^2+... ]

    现在变成了:

    [C_{num-2}^0C_{len}^2+C_{num-2}^1C_{len}^3+C_{num-2}^2C_{len}^4+... ]

    看起来好像很复杂,但是如果考虑插板法的话,就是(inom{len+num-2}{num})

    (O(n^3)dp)就好了。

    代码

    #include<bits/stdc++.h>
    #define N 509
    using namespace std;
    typedef long long ll;
    const int mod=1000000007;
    ll dp[N][N<<1],num[N<<1],l[N],r[N],ni[N],n;
    inline ll rd(){
    	ll x=0;char c=getchar();bool f=0;
    	while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return f?-x:x;
    }
    inline ll power(ll x,ll y){
    	ll ans=1;
    	while(y){if(y&1)ans=ans*x%mod;x=x*x%mod;y>>=1;}
    	return ans;
    }
    inline void MOD(ll &x){x=x>=mod?x-mod:x;}
    int main(){
    	n=rd();
    	for(int i=1;i<=n;++i)ni[i]=power(i,mod-2);
    	for(int i=1;i<=n;++i)l[i]=rd(),r[i]=rd()+1,num[++num[0]]=l[i],num[++num[0]]=r[i];
    	sort(num+1,num+num[0]+1);
    	num[0]=unique(num+1,num+num[0]+1)-num-1;
    	for(int i=1;i<=n;++i){
    		l[i]=lower_bound(num+1,num+num[0]+1,l[i])-num;
    		r[i]=lower_bound(num+1,num+num[0]+1,r[i])-num;
    	}
    	for(int i=0;i<=num[0];++i)dp[0][i]=1;
    	for(int i=1;i<=n;++i){
    		dp[i][0]=1;
    	  for(int j=l[i];j<r[i];++j){
    	  	ll len=num[j+1]-num[j];
    	  	dp[i][j]=dp[i-1][j-1]*len%mod;
    	  	ll su=len-1,cnt=1;
    	    for(int k=i-1;k>=1;--k)if(l[k]<=j&&r[k]>j){
    	       cnt++;
    	       su=su*(len+cnt-2)%mod*ni[cnt]%mod;
    	       if(!su)break;
    	       MOD(dp[i][j]+=dp[k-1][j-1]*su%mod);
    		}
          }
          for(int j=1;j<num[0];++j)(dp[i][j]+=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+mod)%=mod;
        }
        printf("%lld",(dp[n][num[0]-1]-1+mod)%mod);
    	return 0;
    }
    
  • 相关阅读:
    luoguP1160 队列安排 x
    luoguP3366 【模板】最小生成树 x
    cogs服务点设置(不凶,超乖) x
    codevs3269 混合背包 x
    [kuangbin带你飞]专题一 简单搜索 x
    [SWUST1744] 方格取数问题(最大流,最大独立集)
    [SWUST1738] 最小路径覆盖问题(最大流,最小路径覆盖)
    [SWUST1742] 试题库问题(最大流)
    [HDOJ5676]ztr loves lucky numbers(状压枚举,打表,二分)
    [swustoj1739] 魔术球问题 (最大流,最小路径覆盖)
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10832223.html
Copyright © 2011-2022 走看看