zoukankan      html  css  js  c++  java
  • bzoj3193 [JLOI2013]地形生成

    Description

    最近IK正在做关于地形建模的工作。其中一个工作阶段就是把一些山排列成一行。每座山都有各不相同的标号和高度。为了遵从一些设计上的要求,每座山都设置了一个关键数字,要求对于每座山,比它高且排列在它前面的其它山的数目必须少于它的关键数字。
     显然满足要求的排列会有很多个。对于每一个可能的排列,IK生成一个对应的标号序列和等高线序列。标号序列就是按顺序写下每座山的标号。等高线序列就是按顺序写下它们的高度。例如有两座山,这两座山的一个合法排列的第一座山的标号和高度为1和3,而第二座山的标号和高度分别为2和4,那么这个排列的标号序列就是1 2,而等高线序列就是3 4.
     现在问题就是,给出所有山的信息,IK希望知道一共有多少种不同的符合条件的标号序列和等高线序列。

    Input

    输入第一行给出山的个数N。接下来N行每行有两个整数,按照标号从1到N的顺序分别给出一座山的高度和关键数。

    Output

    输出两个用空格分隔开的数,第一个数是不同的标号序列的个数,第二个数是不同的等高线序列的个数。这两个答案都应该对2011取模,即输出两个答案除以2011取余数的结果

    Sample Input

    2
    1 2
    2 2

    Sample Output

    2 2

    HINT 

    对于所有的数据,有1<=N<=1000,所有的数字都是不大于109的正整数。

    正解:组合数学+$dp$。

    把所有山按照高度从大到小排序,相同的一段单独处理。

    对于第一问,算出每次可以插空的数量直接乘法原理即可。

    第二问我们需要一个$dp$,设$f[i][j]$表示放了第$i$座山,$i$在位置$j$的方案数。

    那么第$i+1$座山首先要满足题目给的条件,然后还要在$i$的后面,于是枚举$i+1$的位置$k$,转移即可。

    这样做复杂度是$O(n^{3})$的,我们在$dp$里加上前缀和优化就能做到$O(n^{2})$了。

     1 #include <bits/stdc++.h>
     2 #define il inline
     3 #define RG register
     4 #define ll long long
     5 
     6 using namespace std;
     7 
     8 struct data{ int h,l; }a[1005];
     9 
    10 int f[1005][1005],sum[1005],n,ans1,ans2;
    11 
    12 il int gi(){
    13   RG int x=0,q=1; RG char ch=getchar();
    14   while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
    15   if (ch=='-') q=-1,ch=getchar();
    16   while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
    17   return q*x;
    18 }
    19 
    20 il int cmph(const data &a,const data &b){
    21   if (a.h==b.h) return a.l<b.l; return a.h>b.h;
    22 }
    23 
    24 il void work(RG int l,RG int r){
    25   for (RG int i=1;i<=l && i<=a[l].l+1;++i) f[l][i]=1;
    26   for (RG int i=1;i<=l;++i) sum[i]=(sum[i-1]+f[l][i])%2011;
    27   for (RG int i=l+1,p=2;i<=r;++i,++p){
    28     for (RG int j=1;j<=i && j<=a[i].l+p;++j) f[i][j]=sum[j-1];
    29     for (RG int j=1;j<=i;++j) sum[j]=(sum[j-1]+f[i][j])%2011;
    30   }
    31   RG int res=0;
    32   for (RG int i=1;i<=r;++i) (res+=f[r][i])%=2011;
    33   (ans2*=res)%=2011; return;
    34 }
    35 
    36 int main(){
    37 #ifndef ONLINE_JUDGE
    38   freopen("terrain.in","r",stdin);
    39   freopen("terrain.out","w",stdout);
    40 #endif
    41   n=gi();
    42   for (RG int i=1;i<=n;++i) a[i].h=gi(),a[i].l=gi()-1;
    43   sort(a+1,a+n+1,cmph),ans1=ans2=1;
    44   for (RG int i=1,j;i<=n;i=j+1){
    45     j=i; while (j<n && a[j+1].h==a[j].h) ++j; work(i,j);
    46     for (RG int k=i,l=1;k<=j;++k,++l) (ans1*=min(k,a[k].l+l))%=2011;
    47   }
    48   cout<<ans1<<' '<<ans2; return 0;
    49 }
  • 相关阅读:
    告别ThinkPHP6的异常页面, 让我们来拥抱whoops吧
    ThinkPHP6 上传图片代码demo
    【ThinkPHP6:从TP3升级到放弃】1. 前言及准备工作
    PHP数字金额转换大写金额
    提高PHP开发效率, PhpStorm必装的几款插件
    5分钟弄懂Docker!
    GitHub 上排名前 100 的 IOS 开源库简介
    GitHub 上排名前 100 的 Android 开源库简介
    android线程消息传递机制——Looper,Handler,Message
    Android Activity:四种启动模式,Intent Flags和任务栈
  • 原文地址:https://www.cnblogs.com/wfj2048/p/8111657.html
Copyright © 2011-2022 走看看