[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]\)
\(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 ;
}