洛谷 P5014 水の三角(修改版)

洛谷传送门

思路

考虑将图往左压正,就得到了一个直角三角形的图。

在这个图中,如果没有斜边,则任意时刻走的向下的边都要 \(\ge\) 向右的边。这一部分就是 [SCOI2010] 生成字符串 了。

现在有斜边,考虑枚举走斜边的次数,设 \(u_i\) 为第 \(r\) 行第 \(c\) 列的点,走斜边的次数为 \(k\),那么显然要将走斜边的次数插入总步数中,方案数为 \(C_{row - (i + 1) + col - (i + 1) + i} ^ i\);之后走了 \(k\) 次斜边就相当于从 \((k+1,k+1)\) 出发去 \((r,c)\),直接套生成字符串的式子计算即可。

时间复杂度大约是 \(O(T \sqrt{u_i})\)

代码

code
/*

p_b_p_b txdy
AThousandSuns txdy
Wu_Ren txdy
Appleblue17 txdy

*/

#include <bits/stdc++.h>
#define pb push_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 2000100;
const int N = 2000000;
const ll mod = 998244353;

ll fac[maxn], ifac[maxn], n, a[maxn];

ll qpow(ll b, ll p) {
	ll res = 1;
	while (p) {
		if (p & 1) {
			res = res * b % mod;
		}
		b = b * b % mod;
		p >>= 1;
	}
	return res;
}

void init() {
	fac[0] = 1;
	for (int i = 1; i <= N; ++i) {
		fac[i] = fac[i - 1] * i % mod;
	}
	ifac[N] = qpow(fac[N], mod - 2);
	for (int i = N - 1; ~i; --i) {
		ifac[i] = ifac[i + 1] * (i + 1) % mod;
	}
	for (int i = 1; i <= N; ++i) {
		a[i] = a[i - 1] + i;
	}
}

ll C(ll n, ll m) {
	if (n < m || n < 0 || m < 0) {
		return 0;
	} else {
		return fac[n] * ifac[m] % mod * ifac[n - m] % mod;
	}
}

void solve() {
	scanf("%lld", &n);
	ll row = 1;
	while (a[row] < n) {
		++row;
	}
	ll col = n - a[row - 1], ans = 0;
	for (ll i = 0; i <= min(row, col) - 1; ++i) {
		ll tot = row - (i + 1) + col - (i + 1) + i;
		ans = (ans + C(tot, i) * (C(tot - i, row - (i + 1)) - C(tot - i, row - (i + 1) + 1) + mod) % mod) % mod;
	}
	printf("%lld\n", ans);
}

int main() {
	init();
	int T = 1;
	scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

posted @ 2022-07-21 21:00  zltzlt  阅读(60)  评论(0编辑  收藏  举报