【bzoj3193】[JLOI2013]地形生成 dp+组合数学

好难呀!!!
第一问:
从大到小往里插
不考虑相等的情况
第i大的数有min(i,b[i]+1)个位置可以插
考虑相等的情况
把相等的提出来一起处理
min(i,b[i]+1)+j-i


第二问:
把高度相同的放在一起考虑
ans*=tmp
tmp表示这些高度相同的一共多少种放法可以使等高线不同
现在问题是,把n个球放进m个箱子中,第i个球只能放进编号为[1,b[i]]的箱子中,求方案数。
球都是相同的,两个方案不同,当且仅当存在某一个箱子中的球数不同。
dp[i][j]表示前i个物品只排在前j个位置的方案数
dp[i][j]=dp[i-1][j]+dp[i-1][j-2]+dp[i-1][j-3]+……+dp[i-1][1]  (1<=j<=b[i])
dp[i][j]=dp[i-1][j]+dp[i][j-1]
f[i]+=f[i-1] (1<=i<=b[i])
这里要注意!!
要把高度相同的按照b来排序,否则是不能dp的
tmp=∑dp[num][j] (1<=j<=bmax)


把少于看成不超过,WA了一发


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#define mod 2011
#define maxn 1100 

using namespace std;

struct yts
{
	int h,x;
}a[maxn];

int f[maxn];
int ans1,n,m,ans2;

bool cmp(yts x,yts y)
{
	return x.h>y.h || (x.h==y.h && x.x<y.x);
}

int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++) {scanf("%d%d",&a[i].h,&a[i].x);a[i].x--;}
	sort(a+1,a+n+1,cmp);
	ans1=ans2=1;
	for (int i=1,t=1;i<=n;i=++t)
	{
		while (t<n && a[t+1].h==a[t].h) t++;
		memset(f,0,sizeof(f));
		f[0]=1;
		for (int j=i;j<=t;j++)
		{
			ans1=ans1*(min(i,a[j].x+1)+j-i)%mod;
			for (int k=1;k<=min(i-1,a[j].x);k++) f[k]=(f[k]+f[k-1])%mod;
		}
		int tmp=0;
		for (int j=0;j<=min(i-1,a[t].x);j++) tmp=(tmp+f[j])%mod;
		ans2=ans2*tmp%mod;
	}
	printf("%d %d\n",ans1,ans2);
	return 0;
}


你可能感兴趣的:(【bzoj3193】[JLOI2013]地形生成 dp+组合数学)