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 }
原文地址:https://www.cnblogs.com/wfj2048/p/8111657.html