zoukankan      html  css  js  c++  java
  • 【loj2567】【APIO2016】划艇

    题目

    (N)个位置,每个位置要么不选,要么选([ a_i, b_i ])中的一个数;

    问最后的单调上升序列(mod 1e9+7)有多少种;

    (1 le N le 500)

    题解

    • orz abclzr

    • 直接(dp)最后一位是什么数字的话只能得到31分

    • 将数字离散化分段,第(i)段为([l_i,r_i)),设(f_{i,j})表示第i个位置选的数字在第j段的方案数(第0段表示没有)

      [f_{i,j} = sum_{k=0}^{i-1} sum_{l=0}^{j-1} f_{k,l} imes cal(k+1,i,j) \ ans = sum_{i=1}^n sum_{j=1}^m f_{i,j} \ ]

    • 其中 $ cal(l,r,x) $ 表示 $ [l,r) $ 都不选或者选在第j段并且单调上升的方案数

    • 设 $ [ l,r) $ 这里面有 $ S $ 个包含x区间,x区间的长度为 $ L $ 

      [cal(l,r,x) = sum_{i=0}^{S}(^S_i)(^L_{i+1}) = sum_{i=0}^{S}(^S_{S-i})(^L_{i+1}) \ 思考组合意义:左边选S-i个再在右边选i+1个相当与一起选S+1个\ cal(l,r,x) = (^{S+L}_{S+1}) \ ]

    • 前缀和优化dp即可:(O(n^3))  

      #include<bits/stdc++.h>
      #define ll long long 
      using namespace std;
      const int N=1010,mod=1e9+7;
      int n,tot,sub[N],L[N],R[N],ny[N],l[N],f[N][N];
      void inc(int&x,int y){x+=y;if(x>=mod)x-=mod;}
      int main(){
      //	freopen("boat.in","r",stdin);
      //	freopen("boat.out","w",stdout);
      	scanf("%d",&n);
      	for(int i=1;i<=n;++i){
      		scanf("%d%d",&L[i],&R[i]);
      		sub[++tot]=L[i];
      		sub[++tot]=++R[i];
      	}
      	sort(sub+1,sub+tot+1);
      	tot=unique(sub+1,sub+tot+1)-sub-1;
      	for(int i=1;i<=n;++i){
      		L[i]=lower_bound(sub+1,sub+tot+1,L[i])-sub;
      		R[i]=lower_bound(sub+1,sub+tot+1,R[i])-sub;
      	}
      	ny[1]=1;for(int i=2;i<=n;++i)ny[i]=(ll)(mod-mod/i)*ny[mod%i]%mod;
      	for(int i=0;i<tot;++i)f[0][i]=1;
      	for(int i=1;i<tot;++i)l[i]=sub[i+1]-sub[i];
      	for(int i=1;i<=n;++i){
      		for(int j=L[i];j<R[i];++j){
      			int C=l[j],a=l[j],b=1;
      			for(int k=i-1;~k;--k){
      				inc(f[i][j],(ll)f[k][j-1]*C%mod);
      				if(L[k]<=j&&j<R[k])C=(ll)C*(++a)%mod*ny[++b]%mod;
      			}
      		}
      		for(int j=1;j<tot;++j)inc(f[i][j],f[i][j-1]);
      	}
      	int ans=0;for(int i=1;i<=n;++i)inc(ans,f[i][tot-1]);
      	cout<<ans<<endl;
      	return 0;
      }
      
      //菜兔兔写的部分分
      #include<bits/stdc++.h>
      #define pb push_back
      using namespace std;
      const int N=510,M=2000010,mod=1e9+7;
      int n,a[N],b[N],len[N],sub[M],tot;
      int f[M],g[M];
      void inc(int&x,int y){x+=y;if(x>=mod)x-=mod;}
      int main(){
      //	freopen("boat.in","r",stdin);
      //	freopen("boat.out","w",stdout);
      	scanf("%d",&n);
      	for(int i=1;i<=n;++i){
      		scanf("%d%d",&a[i],&b[i]);
      		for(int j=a[i];j<=b[i];++j)sub[++tot]=j;
      	}
      	sort(sub+1,sub+tot+1);
      	tot=unique(sub+1,sub+tot+1)-sub-1;
      	f[0]=1;for(int i=0;i<=tot;++i)g[i]=1;
      	for(int i=1;i<=n;++i){
      		a[i]=lower_bound(sub+1,sub+tot+1,a[i])-sub;
      		b[i]=lower_bound(sub+1,sub+tot+1,b[i])-sub;
      		for(int j=a[i];j<=b[i];++j)f[j]=g[j];
      		for(int j=a[i];j<=tot;++j)inc(g[j]=f[j],g[j-1]);
      	}
      	cout<<g[tot]-1<<endl;
      	return 0;
      }
      
  • 相关阅读:
    关于各种好玩的神奇函数
    模板——AC自动机
    模板——造数据
    VIM常用操作
    springboot注解
    面试题
    Linux常用命令
    Zookeeper
    对cpu与load的理解及线上问题处理思路
    top
  • 原文地址:https://www.cnblogs.com/Paul-Guderian/p/10840912.html
Copyright © 2011-2022 走看看