题目
题目背景
《咏
D
D
(
X
Y
X
)
\sf DD(XYX)
DD(XYX) 》
红石音乐是主题, O I \rm OI OI 易如小游戏。可怜凡人单线程,谁与校长争第一?
《咏 O U Y E \sf OUYE OUYE 》
润人装弱已毕业,深夜内卷未曾歇。待到今年 I O I \rm IOI IOI,金牌榜首是卷爷。
《咏 D D G \sf DDG DDG 》
卷毛狗,卷不忘磨牙。金牌德牧闪击战,欲成大业先结扎。再把人类杀。
《咏 Respectable Brilliant Queen \textsf{Respectable Brilliant Queen} Respectable Brilliant Queen 》
去年富贵今日贫,弃我不顾狗熊岭。无情最是公交车,只动身体不动心。
《咏 O n e I n D a r k \sf OneInDark OneInDark 》
三年苦学无实力,语文破烂难强基。皇天不与苍生便,常使 O I D \sf OID OID 泪满襟!
题目描述
对于长为
n
n
n 的排列
{
a
1
,
a
2
,
…
,
a
n
}
\{a_1,a_2,\dots,a_n\}
{a1,a2,…,an},若存在
k
∈
[
1
,
n
]
k\in[1,n]
k∈[1,n] 使得
{
a
1
,
a
2
,
…
,
a
k
}
\{a_1,a_2,\dots,a_k\}
{a1,a2,…,ak} 单调递减且
{
a
k
,
a
k
+
1
,
…
,
a
n
}
\{a_k,a_{k+1},\dots,a_n\}
{ak,ak+1,…,an} 单调递增,则
{
a
}
\{a\}
{a} 是 “淡淡谷的”(
slight valley
\text{slight valley}
slight valley)。
称另一个长为 n n n 的排列 { b } \{b\} {b} 是 { a } \{a\} {a} 的 “噬人”,当且仅当 { b } \{b\} {b} 可以被划分为两个子序列 s , t s,t s,t 满足 s ∪ t = b ∧ s ∩ t = ∅ s\cup t=b\land s\cap t=\varnothing s∪t=b∧s∩t=∅,且 s s s 是 { a } \{a\} {a} 的某个前缀而 t t t 是 { a } \{a\} {a} 的某个后缀的倒序。
求有多少个不同的 “淡淡谷的” 的 “噬人” 满足 1 1 1 是序列中第 k k k 个数。答案对大质数取模。
数据范围与提示
1
⩽
k
⩽
n
⩽
5
×
1
0
5
1\leqslant k\leqslant n\leqslant 5\times 10^5
1⩽k⩽n⩽5×105 。
思路
显然需要把 { b } \{b\} {b} 划分为 “淡淡谷的” 和一个下降子序列,且 “淡淡谷的” 的末尾小于下降子序列的末尾。
根据性质和作用的不同,明显有四个子序列:
- L L L,在 “淡淡谷的” 中,在 1 1 1 左侧(含 1 1 1 本身)的下降子序列。
- D 1 D_1 D1,在单减子序列中,在 1 1 1 左侧的部分。
- R R R,在 “淡淡谷的” 中,在 1 1 1 右侧的上升子序列。
- D 2 D_2 D2,在单减子序列中,在 1 1 1 右侧的部分。
影响独立性的限制: D 1 D_1 D1 能够拼接上 D 2 D_2 D2, R R R 的值全部低于 D 2 D_2 D2,以及 ∣ R ∣ + ∣ D 2 ∣ = n − k |R|+|D_2|=n-k ∣R∣+∣D2∣=n−k 。
于是我选择了枚举 ∣ R ∣ |R| ∣R∣,这样立刻得到 ∣ D 2 ∣ |D_2| ∣D2∣,然后考虑 按照值的顺序 作 d p \tt dp dp,因此还需枚举 L L L 不超过 max x ∈ D 2 x \max_{x\in D_2}x maxx∈D2x 的部分。这样就会很麻烦了。
为何按照值的顺序呢?首先,下降子序列实际是二维偏序,要么按值、要么按下标 d p \tt dp dp 。然而它似乎与连续段 d p \tt dp dp 有那么一点共性;这使我陷入错误的第一印象,终未能自拔……
我本应尝试 按照下标作 d p \tt dp dp 。因为 1 1 1 在 k k k 处这个限制,是明显与下标挂钩的;何不就按照下标 d p \tt dp dp 呢?记 f ( i , j ) f(i,j) f(i,j) 为,考虑了前 i i i 个数,目前划分出的两个下降子序列的末尾的排名分别是 1 1 1 和 2 + j ( j ∈ N ) 2{+}j\;(j\in\N) 2+j(j∈N) 。第 ( i + 1 ) (i{+}1) (i+1) 个数更小,则转移到 f ( i + 1 , j + 1 ) f(i{+1},j{+}1) f(i+1,j+1),否则转移到 f ( i + 1 , t ) ( 0 ⩽ t ⩽ j ) f(i{+1},t)\;(0\leqslant t\leqslant j) f(i+1,t)(0⩽t⩽j) 。
我们求出 f ( k − 1 , j ) f(k{-}1,j) f(k−1,j),然后钦定下一位是 1 1 1,得到 min x ′ ∈ D 1 x ′ = j + 3 \min_{x'\in D_1}x'=j{+3} minx′∈D1x′=j+3 的值。注意这是相对排名。接下来把 R R R 和 D 2 D_2 D2 放好。后面这 ( n − k ) (n{-}k) (n−k) 个数,与前面的 ( 1 , j + 2 ] (1,j{+}2] (1,j+2] 之间顺序可调换,所以有系数 ( n − k + j + 1 n − k ) {n-k+j+1\choose n-k} (n−kn−k+j+1) 。后方的内部系数,就是 2 n − k − 1 2^{n-k-1} 2n−k−1,即从左往右填数,要么填 max \max max 要么填 min \min min,但最后一位没得填。
所以问题是求出 f ( k − 1 , x ) f(k{-}1,x) f(k−1,x) 的值。转移式 f ( x , y ) = f ( x − 1 , y − 1 ) + f ( x , y + 1 ) f(x,y)=f(x{-}1,y{-}1)+f(x,y{+}1) f(x,y)=f(x−1,y−1)+f(x,y+1),可以视作坐标系内的行走。只需要按照行走的方向,重建坐标系。在本题中,相当于 x x x 轴上的状态变为 f ( i , i ) f(i,i) f(i,i),然后其上方的状态为 f ( i , i − 1 ) f(i,i{-}1) f(i,i−1) 。这样,移动就是向上和向右(即 x x x 轴正方向)了。限制条件 i ⩾ 0 i\geqslant 0 i⩾0,恰好变为不超过该坐标系内直线 ℓ : y = x \ell:y=x ℓ:y=x 。
初状态有些离谱。但是,只要在序列开头加上假想的 a 0 = + ∞ a_0=+\infty a0=+∞,并强制要求它与 a 1 a_1 a1 不在同一个下降子序列中,就可以发现 f ( 1 , 0 ) = 1 f(1,0)=1 f(1,0)=1 了。得到一个比较经典的类卡特兰数呢!起点恰好在 ( 1 , 1 ) (1,1) (1,1),直接写出 f ( x , y ) = ( 2 x − y − 2 x − 1 ) − ( 2 x − y − 2 x ) f(x,y)={2x-y-2\choose x-1}-{2x-y-2\choose x} f(x,y)=(x−12x−y−2)−(x2x−y−2) 并无难度。
于是就
O
(
n
)
\mathcal O(n)
O(n) 做完了。不幸的是,有人丧心病狂,还要再进一步。把式子写成最终形式
a
n
s
=
2
n
−
k
−
1
∑
j
=
0
k
−
2
f
(
k
−
1
,
j
)
(
n
−
k
+
j
+
1
n
−
k
)
=
2
n
−
k
−
1
∑
j
=
0
k
−
2
[
(
2
k
−
4
−
j
k
−
2
)
−
(
2
k
−
4
−
j
k
−
1
)
]
(
n
−
k
+
j
+
1
n
−
k
)
=
2
n
−
k
−
1
[
(
n
+
k
−
2
n
−
1
)
−
(
n
+
k
−
2
n
)
]
ans=2^{n-k-1}\sum_{j=0}^{k-2}f(k{-1},j){n-k+j+1\choose n-k}\\ =2^{n-k-1}\sum_{j=0}^{k-2}\left[{2k-4-j\choose k-2}-{2k-4-j\choose k-1}\right]{n-k+j+1\choose n-k}\\ =2^{n-k-1}\left[{n+k-2\choose n-1}-{n+k-2\choose n}\right]
ans=2n−k−1j=0∑k−2f(k−1,j)(n−kn−k+j+1)=2n−k−1j=0∑k−2[(k−22k−4−j)−(k−12k−4−j)](n−kn−k+j+1)=2n−k−1[(n−1n+k−2)−(nn+k−2)]
所以式子更简单了。注意一个边界情况是
k
=
n
k=n
k=n,此时
1
1
1 右侧的方案数是
1
1
1,即直接去掉系数
2
n
−
k
−
1
2^{n-k-1}
2n−k−1 即可。
代码
#include <cstdio> // JZM yydJUNK!!!
#include <iostream> // XJX yyds!!!
#include <algorithm> // XYX yydLONELY!!!
#include <cstring> // DDG yydOLDGOD!!!
#include <cctype> // ZXY yydBUS!!!
typedef long long llong;
# define rep(i,a,b) for(int i=(a); i<=(b); ++i)
# define drep(i,a,b) for(int i=(a); i>=(b); --i)
# define rep0(i,a,b) for(int i=(a); i!=(b); ++i)
inline int readint(){
int a = 0, c = getchar(), f = 1;
for(; !isdigit(c); c=getchar()) if(c == '-') f = -f;
for(; isdigit(c); c=getchar()) a = a*10+(c^48);
return a*f;
}
const int MAXN = 1000005;
int jc[MAXN], inv[MAXN];
unsigned int mod;
void prepare(const int &n){
jc[0] = jc[1] = inv[0] = inv[1] = 1;
rep(i,2,n) jc[i] = int(llong(jc[i-1])*i%mod);
rep(i,2,n) inv[i] = int(llong(mod-mod/i)*inv[mod%i]%mod);
rep(i,2,n) inv[i] = int(llong(inv[i])*inv[i-1]%mod);
}
inline llong getC(const int &n, const int &m){
return llong(jc[n])*inv[m]%mod*inv[n-m]%mod;
}
unsigned powtwo[MAXN];
int main(){
int n = readint(), k = readint();
mod = readint();
rep(i,powtwo[0]=1,n){
powtwo[i] = powtwo[i-1]<<1;
if(powtwo[i] > mod) powtwo[i] -= mod;
}
prepare(n<<1);
llong ans = getC(n+k-2,n-1)-getC(n+k-2,n);
if(ans < 0) ans += mod; // be positive
if(n != k) ans = ans*powtwo[n-k-1]%mod;
printf("%lld\n",ans);
return 0;
}
后记
于我而言,写《题目背景》成了一件举足轻重的事。因为很快我将远去,这个账号将会绝笔;这些《题目背景》却忠实地记载了一段传说、一个英雄、一份孤独。
我不配成为 O U Y E \sf OUYE OUYE 的同行者;只是见证,我已经非常庆幸了。