【BZOJ3193】[JLOI2013]地形生成 DP
【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
1 2
2 2
Sample Output
2 2
HINT
对于所有的数据,有1<=N<=1000,所有的数字都是不大于109的正整数。
题解:显然,我们的思路是将所有山按高度排序,然后从大到小扔到序列中去。那么第一问就做完了,考虑第二问。
因为山的高度相同但是关键值不同,那么我们可以认为规定:对于相同高度的山,关键值大的排在关键值小的后面,这样很巧妙的避免了重复。那么直接DP,用f[i]表示在相同高度的山中,最后一个的位置是i的方案数,O(n^2)转移即可。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn=1010; const int mod=2011; int n,ans,sum,last; struct node { int h,k; }p[maxn]; int f[maxn]; inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();} while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar(); return ret*f; } bool cmp2(node a,node b) { return (a.h==b.h)?(a.k<b.k):(a.h>b.h); } int main() { n=rd(); int i,j; for(i=1;i<=n;i++) p[i].h=rd(),p[i].k=rd(); sort(p+1,p+n+1,cmp2),p[0].h=1<<30; for(ans=i=1;i<=n;i++) { if(p[i].h<p[i-1].h) j=0; ans=ans*min(i,p[i].k+j)%mod,j++; } printf("%d ",ans); f[0]=1; for(ans=i=1;i<=n;i++) { if(p[i].h<p[i-1].h) { last=i-1; for(sum=0,j=0;j<=last;j++) sum=(sum+f[j])%mod; memset(f,0,sizeof(f)); for(j=0;j<p[i].k&&j<=last;j++) f[j]=sum; } else { for(sum=0,j=0;j<p[i].k&&j<=last;j++) sum=(sum+f[j])%mod,f[j]=sum; } } for(sum=0,i=0;i<=n;i++) sum=(sum+f[i])%mod; printf("%d",sum); return 0; }
| 欢迎来原网站坐坐! >原文链接<