[JLOI2013]地形生成

题目描述

最近IK正在做关于地形建模的工作。其中一个工作阶段就是把一些山排列成一行。每座山都有各不相同的标号和高度。为了遵从一些设计上的要求,每座山都设置了一个关键数字,要求对于每座山,比它高且排列在它前面的其它山的数目必须少于它的关键数字。 显然满足要求的排列会有很多个。

对于每一个可能的排列,IK生成一个对应的标号序列和等高线序列。标号序列就是按顺序写下每座山的标号。

等高线序列就是按顺序写下它们的高度。例如有两座山,这两座山的一个合法排列的第一座山的标号和高度为1和3,而第二座山的标号和高度分别为2和4,那么这个排列的标号序列就是1 2,而等高线序列就是3 4.

现在问题就是,给出所有山的信息,IK希望知道一共有多少种不同的符合条件的标号序列和等高线序列。

输入输出格式

输入格式:

输入第一行给出山的个数N。接下来N行每行有两个整数,按照标号从1到N的顺序分别给出一座山的高度和关键数。

输出格式:

输出两个用空格分隔开的数,第一个数是不同的标号序列的个数,第二个数是不同的等高线序列的个数。这两个答案都应该对2011取模,即输出两个答案除以2011取余数的结果

输入输出样例

输入样例#1:

2
1 2
2 2

输出样例#1:

2 2

说明

对于所有的数据,有1<=N<=1000,所有的数字都是不大于109的正整数。


题解

给你一个序列,每个序列有权值和关键值
每个数前面比这个数的权值大的数少于关键值

第一问让你求每个点都有标号的方案数
第二问让你求相同高度的标号相同的方案数

我们把序列的排列转化成一个一个数往序列里放
这样如果按照高度降序排序的话对于当前的点,之前所有的点都比它大
所以点i能插进的位置就是\(min(i,p[i].val)\)
这样把每个点方案乘起来第一问就做完了

然后第二问可以转化成一种一种高度往序列里放
这样的话我们就需要按照高度为第一关键字,val为第二关键字排序
这样对于一段相同的高度\([l,r]\)
就相当于有n个无标号的球,m个盒子,每个盒子可以放多个球,第i个球只能放在第\([1,min(i-1,p[i].val-1)]\)个盒子中
这样就可以用\(f[i][j]\)表示前i个球放在了前j个盒子里的方案数
\(f[i][j] = \sum_{k=0}^{k<=min(i-1,p[r].val-1}f[i - 1][k]\)
然后让答案乘上\(\sum_{k=0}^{k<=min(i-1,p[r].val-1}{f[i][k]}\)就好辣

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int M = 1005 ;
const int mod = 2011 ;
using namespace std ;
inline int read() {
    char c = getchar() ; int x = 0 , w = 1 ;
    while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
    while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
    return x*w ;
}

int n , Ans1 = 1 , Ans2 = 1 , Nxt , f[M] ;
struct Hill { int val , High ; } p[M] ;
bool CmpHv(Hill a , Hill b) 
{ return a.High == b.High ? a.val < b.val : a.High > b.High ; }
int main() {
    n = read() ;
    for(int i = 1 ; i <= n ; i ++) p[i].High = read() , p[i].val = read() - 1 ;
    sort(p + 1 , p + n + 1 , CmpHv) ;
    for(int i = 1 ; i <= n ; i = Nxt + 1) {
        Nxt = i ;
        while(p[Nxt + 1].High == p[i].High) ++ Nxt ;
        memset(f , 0 , sizeof(f)) ; f[0] = 1 ; int ret = 0 ;
        for(int j = i ; j <= Nxt ; j ++) {
            Ans1 = (Ans1 * (min(p[j].val + 1 , i) + j - i)) % mod ;
            for(int k = 1 ; k <= min(i - 1 , p[j].val) ; k ++) 
                f[k] = (f[k] + f[k - 1]) % mod ;
        }
        for(int j = 0 ; j <= min(i - 1 , p[Nxt].val) ; j ++) ret = (ret + f[j]) % mod ;
        Ans2 = (Ans2 * ret) % mod ;
    }
    cout << Ans1 << " " << Ans2 << endl ;
    return 0 ; 
}

猜你喜欢

转载自www.cnblogs.com/beretty/p/10087893.html