• [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 ; 
    }
    
  • 相关阅读:
    广播接收者的生命周期?
    如何让自己的广播只让指定的 app 接收?
    在 manifest 和代码中如何注册和使用 BroadcastReceiver?
    请描述一下 BroadcastReceiver?
    说说 Activity、Intent、Service 是什么关系
    什么是IntentService?有何优点?
    Activity 怎么和 Service 绑定,怎么在 Activity 中启动自己对应的 Service?
    Service 是否在 main thread 中执行, service 里面是否能执行耗时的操作?
    两个 Activity 之间跳转时必然会执行的是哪几个方法?
    如何保存 Activity 的状态?
  • 原文地址:https://www.cnblogs.com/beretty/p/10087893.html
Copyright © 2020-2023  润新知