快合格考了发现自己啥都不会没啥希望过,于是又回来刷题了。。。
这个$DP$很有意思。
第一问就是个套路$DP$,按高度降序排序,依次把山插进去。因为题目要求的是严格大于,排序时高度相同的按关键值降序排序就好了。
第二问一开始想了个$O(n)$的假做法,显然数据范围是要$O(n^2)$的。。。
好难啊不会了告辞
还是排好序,我们考虑把相同高度的山一块插进去。对于每一段相同高度的区间$[l,r]$设$f(i,j)$为这段区间中前$i$座山,插进所有山中前$j$座山的前面的方案数。
每座山要么插到第$j$座山前面($j\le $关键值),有$f(i-1,j)$种方案;要么插到前$j-1$座山前面,有$f(i,j-1)$种方案。
也就是$f(i,j)=f(i,j-1)+f(i-1,j)$。
因为相同高度的山是单独考虑的,根据乘法原理答案为所有$f(r-l+1,min\{l,H[r].cnt\})$的乘积。
$f$要滚起来,要不然清空太慢。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <stack>
#define maxn 1005
#define inf 0x3f3f3f3f
const int mod = 2011;
using namespace std;
inline int read(){
int x=0,y=0;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return y?-x:x;
}
struct hill{
int h,cnt;
bool operator < (const hill &x)const{
if(h!=x.h)return h>x.h;
return cnt<x.cnt;
}
}H[maxn];
int f[2][maxn];
int main(){
int n=read(),ans=1,sum1=0,sum2=0,p;
for(register int i=1;i<=n;++i)H[i].h=read(),H[i].cnt=read();
sort(H+1,H+1+n);
for(register int i=2;i<=n;++i){
if(H[i].h==H[i-1].h)++sum1;
else sum2=i-1,sum1=0;
ans=1ll*ans*(min(H[i].cnt-1,sum2)+sum1+1)%mod;
}
printf("%d ",ans);
ans=1;
for(register int i=1;i<=n;i=p+1){
memset(f,0,sizeof f);
p=i+1;
while(p<=n&&H[p].h==H[i].h)++p;
--p;
for(register int j=1;j<=i;++j)f[0][j]=1;
for(register int j=i;j<=p;++j)
for(register int k=1;k<=i;++k){
f[j-i+1&1][k]=f[j-i+1&1][k-1];
if(k<=H[j].cnt)(f[j-i+1&1][k]+=f[j-i&1][k])%=mod;
}
ans=1ll*ans*f[p-i+1&1][min(i,H[p].cnt)]%mod;
}
printf("%d\n",ans);
}