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
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 }