【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

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