bzoj3193【JLOI2013】地形生成

3193: [JLOI2013]地形生成

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 277   Solved: 135
[ Submit][ Status][ Discuss]

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的正整数。




第一问:可以发现对一座山有影响的只可能是比它高的山,所以我们可以将山按高度从大到小排序,依次插入每座山。对于高度相同的山一起处理,按关键值从小到大排序,然后将每座山能插入的位置数乘到答案中,即min(i,a[i].key+1)+num-1,num为它在高度相同的山中的排名。

第二问:为了不重复计算,我们每次将高度相同的山拿出来,然后让插入之后的顺序也不改变。这样就可以DP计算,f[i][j]=f[i-1][0]+f[i-1][1]+……+f[i-1][j],其实f数组还可以降到一维。注意每次计算时要将f数组清零。




#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define maxn 1005
#define mod 2011
using namespace std;
int n,ans1=1,ans2=1,f[maxn];
struct data{int h,k;}a[maxn];
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline bool cmp(data x,data y)
{
	return x.h==y.h?x.k<y.k:x.h>y.h;
}
int main()
{
	int i,j;
	n=read();
	F(i,1,n) a[i].h=read(),a[i].k=read()-1;
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;i=j)
	{
		memset(f,0,sizeof(f));
		f[0]=1;
		for(j=i;j<=n&&a[i].h==a[j].h;j++)
		{
			ans1=ans1*(min(i,a[j].k+1)+j-i)%mod;
			for(int k=1;k<i&&k<=a[j].k;k++) f[k]=(f[k]+f[k-1])%mod;
		}
		int sum=0;
		for(int k=0;k<i&&k<=a[j-1].k;k++) sum=(sum+f[k])%mod;
		ans2=(ans2*sum)%mod;
	}
	printf("%d %d\n",ans1,ans2);
	return 0;
}


你可能感兴趣的:(dp,bzoj)