2025.2.17 鲜花

机关 题解

T3

MARENOL

要是放这个歌机房会有人能欣赏吗???

来自b站视频av35346701下的评论

应该是 LeaF 本人自己写的

侵删

感觉不是难题。

题目中的 \(k\)\(1\) 的位置在这里记作 \(m\)

容易发现, \(a\) 序列一定是先单调递降到 \(1\) 在单调递增的 V 字,考虑每次弹出最前和最后,所以 \(b\) 序列在 \(1\) 之前的部分一定可以拆成两个单调递降的子序列,并且能拆的一定可以生成。

\(1\) 后面取出的方案数是显的,其在 \(a\) 上只有两种排列方式即单增或单降,但其是等价的,而每次只能取最前或最后,于是是 \(2 ^ {x - 1}\)\(x\) 是剩余颜色个数)。

考虑求出 \(1\) 之前的部分,用两个序列 \(A, B\) 表示其划分成的子序列,并且 \(A\) 是拿 \(1\) 前一步拿的一边,为了不重复计算我们定义一个序列的划分是依次遍历每个值,如果能放入 \(A\) 就放入 \(A\),否则放入 \(B\),容易证明其会构成双射。

考虑计数,设 \(dp_{i,j}\) 表示当前是 \(b\) 的第 \(i\) 位,\(A\) 的最后一位是 \(j\) 的方案数,考虑转移,分讨第 \(i\) 位放到哪里了,若放到 \(A\) 则第 \(i\) 位必然填 \(j\),且可以从 \(dp_{i - 1, k}(k>j)\) 转移,若放到 \(B\) 则必然填剩余的最大的,若填较小的则更大的数就无处可去了(因为 \(1\) 右边的数一定小于 \(1\) 左边 \(B\) 中的数,而 \(B\) 又是递降的),可以从 \(dp_{i - 1, j}\) 转移过来。

于是方程就是:

\[dp_{i, j} = (\sum_{k = j + 1} ^ {l} dp_{i - 1, k}) + dp_{i - 1, j}= \sum_{k = j} ^ {l} dp_{i - 1, k} \]

注意到 \(k\) 的上节 \(l\),其并不总是 \(n\),原因是当转移 \(dp_{i, j}\) 时,一共剩下 \(n - i\) 个元素,而 \([1, j - 1]\) 是必然剩下的,否则非法,于是 \(j - 1 \le n - i\),即 \(l = n - i + 1\)

上个前缀和就可以 \(\mathcal{O}(n ^ 2)\) 求了,容易想到放到格路上考虑。

先给一组固定的起点和终点,设 \(dp_{0, n + 1} = 1\),终点是 \(\sum\limits_{i = 2}^{n - m} dp_{m - 1,i} = dp_{m, 2}\),于是问题变成了从 \((0, n)\) 走到 \((m, 2)\),格路形如:

将其推平,最高位是不能水平向右转移的,加一条线表示永不碰到,于是就变成了:

直接卡特兰数即可,一点小问题是因为最后一行的竖线存在,答案事实上求了前缀和,可以用 \((m, 2)\)\((m, 3)\) 差分一下,或者直接求到 \((m - 1, 2)\) 即可。

Code

/* Local File
in_out/in.in
in_out/out.out
*/
#include <bits/stdc++.h>
using namespace std;
using llt = long long;
using ull = unsigned long long;
using llf = long double;
#define endl '\n'
#ifndef LOCAL
#undef assert
#define assert 0 &&
#define cerr 0 && cerr
FILE *InFile = freopen("game.in", "r", stdin), *OutFile = freopen("game.out", "w", stdout);
#endif

const int N = 5e5 + 3, M = N * 2 - 3;
int n, m, MOD, ans = 0;
int aas, fac[M], ivf[M];

int Fpw(int a, int b){
	if(b < 0) return 1;
	int ans = 1;
	while(b){
		if(b & 1) ans = 1ll * ans * a % MOD;
		a = 1ll * a * a % MOD, b >>= 1;
	}
	return ans;
}

int C(int a, int b){
	return a < b ? 0 : 1ll * fac[a] * ivf[b] % MOD * ivf[a - b] % MOD;
}
int P(int a, int b, int c, int d){
	int l = c - a, r = d - b;
	return C(l + r, l);
}
int Cat(int a, int b, int c, int d){
	return (1ll * P(a, d, c, b) - P(a, b - c + 2, n + 2 - d, b)) % MOD;
}

int main(){
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	cin >> n >> m >> MOD;
	if(n == 1)
		return cout << 1, 0;
	fac[0] = 1;
	for(int i = 1; i <= M - 3; ++i)
		fac[i] = 1ll * fac[i - 1] * i % MOD;
	ivf[M - 3] = Fpw(fac[M - 3], MOD - 2);
	for(int i = M - 3; i; --i)
		ivf[i - 1] = 1ll * ivf[i] * i % MOD;
	cout << ((1ll * Cat(0, n, m, 2) - Cat(0, n, m, 3)) % MOD * Fpw(2, n - m - 1) % MOD + MOD) % MOD;
}
P


posted @ 2025-02-17 20:18  xrlong  阅读(98)  评论(10)    收藏  举报

Loading