Live2D

[AGC040F] Two Pieces 题解

link

Solution

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

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

  • \(x,d\)\(+1\)

  • \(d\to d-1(d\ge 2)\)

  • \(d\to 0\)

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

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

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

有了上面两个性质,那么我们就可以看出我们最后一次 \(3\) 操作前面一次的 \(d\) 一定是 \((B-k)-(B-A)=A-k\),而我们在 \(0,1,2,...,A-k\) 每个 \(d\) 权值后面都可以在最后一个位置后面加入一次 \(3\) 操作。那么贡献即是:\(\binom{n-B-k-1+A-k}{A-k}\)

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

Code

#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 @ 2022-11-10 19:05  Dark_Romance  阅读(35)  评论(0编辑  收藏  举报