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;
    }
    
  • 相关阅读:
    Linked List Cycle leetcode java (链表检测环)
    Remove Duplicates from Sorted List II leetcode java
    Remove Duplicates from Sorted List leetcode java
    Merge Two Sorted Lists leetcode java
    Swap Nodes in Pairs leetcode java
    Median of Two Sorted Array leetcode java
    阿里云最便宜的四种域名注册
    nohup和&后台运行,进程查看及终止
    ipv6转ipv4 NAT64与DNS64基本原理概述
    ros使用pppoe拨号获取ipv6,并且下发IPV6的dns到客户机win7
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10832223.html
Copyright © 2011-2022 走看看