2024.2.17 鲜花

机关 题解

T3

MARENOL

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

来自b站视频av35346701下的评论

应该是 LeaF 本人自己写的

侵删

感觉不是难题。

题目中的 k1 的位置在这里记作 m

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

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

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

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

于是方程就是:

dpi,j=(k=j+1ldpi1,k)+dpi1,j=k=jldpi1,k

注意到 k 的上节 l,其并不总是 n,原因是当转移 dpi,j 时,一共剩下 ni 个元素,而 [1,j1] 是必然剩下的,否则非法,于是 j1ni,即 l=ni+1

上个前缀和就可以 O(n2) 求了,容易想到放到格路上考虑。

先给一组固定的起点和终点,设 dp0,n+1=1,终点是 i=2nmdpm1,i=dpm,2,于是问题变成了从 (0,n) 走到 (m,2),格路形如:

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

直接卡特兰数即可,一点小问题是因为最后一行的竖线存在,答案事实上求了前缀和,可以用 (m,2)(m,3) 差分一下,或者直接求到 (m1,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 @   5k_sync_closer  阅读(66)  评论(9编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
历史上的今天:
2024-02-17 2024初三集训模拟测试1
点击右上角即可分享
微信分享提示