题意
(n) 元素各有一个高度 (h) 和关键数字 (b) 。求有多少个下标序列和高度序列,满足对任意 (i),(j< i) 且 (h_j < h_i)的 (j) 个数小于 (b_i)
- (n leq 1000).
分析
-
因为只有比 (i) 高的元素才会影响 (i) ,所以考虑把所有元素按照高度降序排列。
-
下标序列
-
考虑每个元素插入之前的排列中,一共有 (min(b_i,i)) 种方案。
-
考虑相同高度的元素按照 (b) 的大小升序排列,这样能够保证后放的元素一定可以放在先放的元素后面。
-
-
高度序列
- 做法类似之前,只是处理相同元素时要求每次要保证 每次放的位置 (geq) 上一次放的位置
-
总时间复杂度为 (O(n^2)) 。
处理组合计数问题的技巧:插入数字或者保留位置;
排列 ( ightarrow) 组合:强制放置有序即可;
代码
#include<bits/stdc++.h>
using namespace std;
#define go(u) for(int i=head[u],v=e[i].to;i;i=e[i].last,v=e[i].to)
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define pb push_back
typedef long long LL;
inline int gi(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
return x*f;
}
template<typename T>inline bool Max(T &a,T b){return a<b?a=b,1:0;}
template<typename T>inline bool Min(T &a,T b){return b<a?a=b,1:0;}
const int N=1007,mod=2011;
void add(int &a,int b){a+=b;if(a>=mod) a-=mod;}
int n;
int ans1=1,ans2=1,f[N][N],s[N][N];
struct data{
int a,b;
data(){}data(int a,int b):a(a),b(b){}
bool operator <(const data &rhs)const{
if(a!=rhs.a) return a>rhs.a;
return b<rhs.b;
}
}v[N];
int main(){
n=gi();
rep(i,1,n) v[i].a=gi(),v[i].b=gi()-1;
sort(v+1,v+1+n);
for(int i=1,j=1;i<=n;i=j+1,j=i){
while(j+1<=n&&v[j+1].a==v[i].a) ++j;
rep(k,i,j) ans1=ans1*(min(v[k].b+1,i)+k-i)%mod;
}
for(int i=1,j=1;i<=n;i=j+1,j=i){
while(j+1<=n&&v[j+1].a==v[i].a) ++j;
s[i-1][0]=1;
rep(z,1,i-1) s[i-1][z]=s[i-1][z-1];
rep(k,i,j)
for(int z=0;z<=i-1;++z){
s[k][z]=z?s[k][z-1]:0;
if(z<=v[k].b) add(s[k][z],s[k-1][z]);
}
ans2=ans2*(s[j][i-1])%mod;
}
printf("%d %d
",ans1,ans2);
return 0;
}