挺有趣的一道 $dp$,两问实际上就相当于是第一问是第二问的部分分
第一问
一开始以为要 $dp$,然而并不用
对于这种高度然后求方案数的题,可以只考虑其相对位置,因为只要所有相对位置确定了,那么整个序列就唯一确定了
首先肯定要先将它们以高度为第一关键字(由大到小),关键值为第二关键字(从小到大)排序
那么对于第 $i$ 座山,它就会有 $\min (i, key_i)$ 个相对位置可以占,因为有相同高度的山峰,所以还会多出 $same$ ($i$ 前面与其高度相同的山峰的个数)个位置
那么 $ans_1 = \prod\limits_{i = 1}^n min (i, key_i + same)$
第二问
症结还是在于相同高度的山峰会产生重复
但是显然如果一次性确定好所有相同山峰的位置是不会产生重复的,故考虑将每一组相同高度的山峰放在一起处理
为了避免重复,需要强制令这些相同高度的山峰放置有序,即后放的一定在先放的后面,那么就可以令 $f_{i, j}$ 表示(当前组相同高度山峰)前 $i$ 个放在前 $j$ 个位置上,并且第 $i$ 放在第 $j$ 个位置的方案数,则有(下示方程表示区间 $[l, r]$ 的相同高度山峰组)
$$
\begin{aligned}
f_{i, j} &= \sum\limits_{k = 1}^j f_{i - 1, k} (j \in [0, \min (l, key_i) - 1]) \\
&= f_{i - 1, j} + f_{i, j - 1}
\end{aligned}
$$
然后实际上第一维是没用的,再省掉就行了
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| #include <iostream> #include <cstdio> #include <cstring> #include <algorithm>
#define MOD 2011
using namespace std;
typedef long long LL;
const int MAXN = 1000 + 10;
LL f[MAXN]= {0};
struct hillSt { int high; int key;
hillSt (int fhigh = 0, int fkey = 0) : high (fhigh), key (fkey) {} bool operator < (const hillSt& p) const { if (high == p.high) return key < p.key; return high > p.high; } } ;
int N; hillSt hill[MAXN];
int getnum () { int num = 0; char ch = getchar ();
while (! isdigit (ch)) ch = getchar (); while (isdigit (ch)) num = (num << 3) + (num << 1) + ch - '0', ch = getchar ();
return num; }
int main () { N = getnum (); for (int i = 1; i <= N; i ++) hill[i].high = getnum (), hill[i].key = getnum (); sort (hill + 1, hill + N + 1); LL ans1 = 1; int same = 0; for (int i = 1; i <= N; i ++) { hill[i].high == hill[i - 1].high ? same ++ : same = 0; ans1 = ans1 * 1ll * min (i, hill[i].key + same) % MOD; } LL ans2 = 1; for (int l = 1; l <= N; l ++) { int r; for (r = l; r <= N && hill[r + 1].high == hill[r].high; r ++); memset (f, 0, sizeof (f)); f[0] = 1; for (int i = l; i <= r; i ++) for (int j = 1; j <= min (l, hill[i].key) - 1; j ++) f[j] = (f[j - 1] + f[j]) % MOD; LL total = 0; for (int j = 0; j <= min (l, hill[r].key) - 1; j ++) total = (total + f[j]) % MOD; ans2 = ans2 * total % MOD; swap (l, r); } cout << ans1 << ' ' << ans2 << endl;
return 0; }
|