【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} \times 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;
    }

原文地址:https://www.cnblogs.com/Paul-Guderian/p/10840912.html

时间: 2024-10-13 10:56:26

【loj2567】【APIO2016】划艇的相关文章

计数难题5:[APIO2016]划艇

计数难题5:[APIO2016]划艇 标签(空格分隔): 计数难题题选 题目大意: 给定\(n\)个区间\([l_i,r_i]\). 你可以从第\(i\)个区间中选出一个整数元素\(a_i\in [l_i,r_i]\),也可以不选. 要求选出的元素按标号顺序排列后构成一个严格单调递增序列. 求至少选出一个元素的合法方案数. 答案对\(10^9+7\)取模. 数据范围:\(n\leq 500\) , \(l_i\leq r_i \leq 10^9\) . 题解 可以想到把区间离散化. 设\(f_{

[APIO2016]划艇

题目描述 在首尔城中,汉江横贯东西.在汉江的北岸,从西向东星星点点地分布着 NNN 个划艇学校,编号依次为 111 到 NNN.每个学校都拥有若干艘划艇.同一所学校的所有划艇颜色相同,不同的学校的划艇颜色互不相同.颜色相同的划艇被认为是一样的.每个学校可以选择派出一些划艇参加节日的庆典,也可以选择不派出任何划艇参加.如果编号为 iii 的学校选择派出划艇参加庆典,那么,派出的划艇数量可以在 aia_ia?i?? 至 bib_ib?i?? 之间任意选择(ai≤bi). 值得注意的是,编号为 iii

[Codeforces 1295F]Good Contest(DP+组合数学)

[Codeforces 1295F]Good Contest(DP+组合数学) 题面 有一个长度为\(n\)的整数序列,第\(i\)个数的值在\([l_i,r_i]\)中随机产生.问这个序列是一个不上升序列的概率(模\(998244353\)意义下). \(n \leq 50,l_i,r_i \leq 998244351\) 分析 和[APIO2016]划艇几乎一模一样.可惜比赛的时候时间不够. 首先把问题转化成求最长不上升序列的数量. 我们把这些区间离散化,分割成两两之间不互相覆盖的若干个区间

BZOJ 4584 【APIO2016】 赛艇

题目链接:赛艇 讲道理好好的Boat为啥要翻译成赛艇呢--题面中不也是划艇么-- 这道题考虑一下dp.由于划艇数量过于庞大,所以肯定不能直接记录到dp状态中.所以一个想法就是把数量离散化,然后把每个学校的数量在哪一段内记录下来.也就是说\(f_{i,j,k}\)表示前\(i\)个学校,第\(i\)所学校派出的划艇数量在区间\(j\)内,并且区间\(j\)内共有\(k\)个学校的方案数.然后分类讨论一下转移: 当\(k\ne 1\)时,有: \begin{aligned}f_{i,j,k} &=\

[BZOJ4584][Apio2016]赛艇

试题描述 在首尔城中,汉江横贯东西.在汉江的北岸,从西向东星星点点地分布着个划艇学校,编号依次为到.每个学校都拥有若干艘划艇.同一所学校的所有划艇颜色相同,不同的学校的划艇颜色互不相同.颜色相同的划艇被认为是一样的.每个学校可以选择派出一些划艇参加节日的庆典,也可以选择不派出任何划艇参加.如果编号为的学校选择派出划艇参加庆典,那么,派出的划艇数量可以在Ai至Bi之间任意选择(Ai<=Bi).值得注意的是,编号为i的学校如果选择派出划艇参加庆典,那么它派出的划艇数量必须大于任意一所编号小于它的学校

CTSC2016&amp;&amp;APIO2016爆零记

CTSC2016&&APIO2016爆零记 前言:人生第一次写(骗)爆(访)零(问)记(量),心里还是有点小激动呢.不过由于本文作者语文水平低下,如果发现用词不当或只会记流水账,请谅解. CTSC Day0: CCF大发慈悲让我们入住了5星级酒店昆(百)泰酒店. 不过也有一点不兹磁的地方,就是酒店离学校大概要步行半个小时,对于我这种懒人大概是天大的灾难吧(雾).于是这次比赛就强行变成了CTSC&&APIO远足营. 第一次看见70块钱一瓶零下八度不结冰的矿泉水,然而家穷喝不起

UOJ#204 【APIO2016】Boat

Time Limit: 70 Sec  Memory Limit: 256 MBSubmit: 559  Solved: 248 Description 在首尔城中,汉江横贯东西.在汉江的北岸,从西向东星星点点地分布着个划艇学校,编号依次为到.每个学校都 拥有若干艘划艇.同一所学校的所有划艇颜色相同,不同的学校的划艇颜色互不相同.颜色相同的划艇被认为是一 样的.每个学校可以选择派出一些划艇参加节日的庆典,也可以选择不派出任何划艇参加.如果编号为的学校选择 派出划艇参加庆典,那么,派出的划艇数量可

【APIO2016】Gap

[APIO2016]Gap 交互题 对于30%的数据,直接从s=0,t=1e18开始,每次让s=mn+1,t=mx-1,每一次可以得到两个,可以在(n+1)/2的时间内得到 对于其他数据,我们先求出最大最小值,求出len=(mx-mn)/(n-1),这相当与是一个"平均数",如果我将区间分为若干段长度为len的区间,只记录每个区间内的最大值和最小值,这样被漏算的那些点,他们最多有len-1的贡献,而这个还达不到平均数,所以肯定不会影响答案,所以就可以在3*n以内求出序列有用的部分了.

BZOJ 4584 [Apio2016]赛艇 ——动态规划

Subtask 1 直接$N^2$ $DP$,就可以了 Subtask 2 用$f[i][j]$表示当前位置为$i$,结束元素为$j$的方案数. Subtask 3 看下面 Subtask 4 首先可以枚举一段序列选择同一个重叠的区间,然后一些可以不选,如果选的话要求上升. 然后很容易得到方程,离散化之后就可以$N^4$直接做了. 然后并不会优化,看了题解. 想了想写不出来. 抄代码啦! #include <map> #include <ctime> #include <cm