Live2D

[AGC040F] Two Pieces 题解

link

Solution

这个题真的挺难的。/kk 看了一个下午的题解才搞懂。/fn

我们发现我们如果设状态 (x,d) 表示前面的一个点在 x,另一个在 xd,那么三种操作相当于:

  • x,d+1

  • dd1(d2)

  • d0

很显然 2 操作 d2 是为了不在 d=1 的时候与 3 算重。另外一个可以观察到的性质就是 1 操作会操作 B 次。

那么我们先考虑没有三操作的情况。可以发现相当于从 (1,1)(B,BA),每次要么右上要么向下,且不能碰到 x 轴的方案数,这个可以用翻折法算出时 (A+B1A)(A+B1B)

考虑有三操作的情况,假设我们使用 2 操作 k 次,那么 3 操作就会使用 nBk 次。我们发现如果抽出所有的 3 操作,那么显然是合法的,并且最后会在 (B,Bk) 处,而我们需要到达 (B,BA)。注意到我们设第 i 次操作后纵坐标为 di,那么我们在 i 之后加入一个 3 操作就需要满足当 j>idj>di,因为我们相当于把 i 及其以后的 d 都减去 di 。这就可以看出同一权值的 d 如果后面有加入 3 操作的,那么一定是最后一个位置。另外一个性质是假设在集合 S 之后加入了 3 操作,那么最后纵坐标会减少 maxxSdx

有了上面两个性质,那么我们就可以看出我们最后一次 3 操作前面一次的 d 一定是 (Bk)(BA)=Ak,而我们在 0,1,2,...,Ak 每个 d 权值后面都可以在最后一个位置后面加入一次 3 操作。那么贡献即是:(nBk1+AkAk)

那么我们就可以 Θ(n) 解决这个问题了。

Code

Copy
#include <bits/stdc++.h> using namespace std; #define Int register int #define mod 998244353 #define MAXN 20000005 template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;} template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);} template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');} template <typename T> inline void chkmax (T &a,T b){a = max (a,b);} template <typename T> inline void chkmin (T &a,T b){a = min (a,b);} int n,A,B,fac[MAXN],ifac[MAXN]; int mul (int a,int b){return 1ll * a * b % mod;} int dec (int a,int b){return a >= b ? a - b : a + mod - b;} int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;} int qkpow (int a,int b){ int res = 1;for (;b;b >>= 1,a = mul (a,a)) if (b & 1) res = mul (res,a); return res; } void Add (int &a,int b){a = add (a,b);} void Sub (int &a,int b){a = dec (a,b);} int binom (int a,int b){return a >= b ? mul (fac[a],mul (ifac[b],ifac[a - b])) : 0;} signed main(){ read (n,A,B);int up = 2e7; fac[0] = 1;for (Int i = 1;i <= up;++ i) fac[i] = mul (fac[i - 1],i); ifac[up] = qkpow (fac[up],mod - 2);for (Int i = up;i;-- i) ifac[i - 1] = mul (ifac[i],i); int ans = 0; for (Int k = 0;k <= A && k <= n - B;++ k){ int v = B == 0 ? 1 : dec (binom (B + k - 1,k),binom (B + k - 1,B)); if (k == A) Add (ans,v); else Add (ans,mul (v,binom (n - B - k - 1 + A - k,A - k))); } write (ans),putchar ('\n'); return 0; }
posted @   Dark_Romance  阅读(40)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示