LOJ#2567. 「APIO2016」划艇 离散化+DP

运用到了 NOI2019 机器人那道题的技巧.    

考虑对区间进行离散化,然后设当前枚举到的两个端点为 $[l,r]$.  

先处理 $[l,r)$,会遇到 $\sum_{i=1}^{n} \binom{len}{i} \binom{k}{i}$ 这个式子.  

这个式子可以直接 $O(1)$ 组合数算,但是我比较懒用 $O(n^2)$ 递推算的(反正不影响总复杂度)      

处理完 $[l,r)$ 后再处理 $[r,r]$ 以保证所有边界情况都被考虑好.   

code: 

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 704  
#define ll long long 
#define mod 1000000007
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std; 
int n;  
int inv[N],iv[N],fac[N],g[N],A[N];       
int a[N],b[N],e[N<<1],dp[N][2];  
void init() {
    inv[1]=1,fac[0]=1;  
    for(int i=1;i<N;++i) fac[i]=(ll)fac[i-1]*i%mod;  
    for(int i=2;i<N;++i) iv[i]=inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod;    
    iv[0]=iv[1]=1;  
    inv[0]=1;  
    for(int i=1;i<N;++i) inv[i]=(ll)inv[i-1]*inv[i]%mod;  
} 
int C(int x,int y) {
    return (ll)fac[x]*inv[y]%mod*inv[x-y]%mod; 
}
int ADD(int x,int y) {
    return (x+y)>=mod?x+y-mod:x+y;    
}
int main() {
    // setIO("input");
    init(); 
    int x,y,z,tot=0;    
    scanf("%d",&n);   
    for(int i=1;i<=n;++i) {
        scanf("%d%d",&a[i],&b[i]);    
        e[++tot]=a[i],e[++tot]=b[i]+1;  
    }    
    sort(e+1,e+1+tot);       
    dp[0][0]=1;   
    for(int i=1;i<=tot;++i) {
        if(e[i]!=e[i-1]) {
            int len=e[i]-e[i-1]-1;          
            if(len) {
                A[0]=1;                        
                for(int j=1;j<=min(n,len);++j) {
                    A[j]=(ll)A[j-1]*iv[j]%mod*(len-j+1)%mod;   
                }     
                for(int j=1;j<=n;++j) 
                {
                    g[j]=0;  
                    for(int t=1;t<=min(len,j);++t)             
                        g[j]=ADD(g[j],(ll)A[t]*C(j-1,t-1)%mod);                          
                }   
                for(int j=1;j<=n;++j) {                      
                    dp[j][1]=0;   
                    if(a[j]<=e[i-1]&&b[j]>=e[i-1])   {
                        int cnt=0;         
                        for(int k=j;k>=1;--k) {   
                            if(a[k]<=e[i-1]&&b[k]>=e[i-1]) {
                                ++cnt;                  
                            }
                            if(cnt) dp[j][1]=ADD(dp[j][1],(ll)g[cnt]*dp[k-1][0]%mod); 
                        }
                    }
                }    
                for(int j=1;j<=n;++j) {
                    dp[j][0]=ADD(dp[j][0],dp[j][1]);   
                    dp[j][1]=0;  
                }
            }            
            for(int j=1;j<=n;++j) {        
                if(a[j]<=e[i]&&b[j]>=e[i]) {
                    for(int k=0;k<j;++k) dp[j][1]=ADD(dp[j][1],dp[k][0]);              
                }
            }
            for(int j=1;j<=n;++j) {
                dp[j][0]=ADD(dp[j][0],dp[j][1]); 
                dp[j][1]=0;  
            }
        }
    }
    int ans=0;
    for(int i=1;i<=n;++i) {
        ans=ADD(ans,dp[i][0]);  
    }
    printf("%d\n",ans);  
    return 0; 
}

  

posted @ 2020-08-03 22:20  EM-LGH  阅读(151)  评论(0编辑  收藏  举报