UVA1478 Delta Wave 题解

洛谷传送门

思路

若不能往右走,则本题就是卡特兰数。

现在加上可以往右走的条件,可以在一开始都往右走的前提下任选 \(k\) 个右上,\(k\) 个右下,并且不能碰到 \(y = -1\)。因此方案数为:

\[\sum\limits_{k=1}^{\left\lfloor\frac{n}{2}\right\rfloor} C_{n}^{2k} f_k + 1 \]

其中 \(f_k\) 为第 \(k\) 项卡特兰数,\(+1\) 是因为还要算全部往右走的方案。

直接高精计算显然会 T,考虑算出连续两项的比值 \(= \dfrac{(n-2k+1)(n-2k+2)}{k(k+1)}\),就可以高精乘低精 + 高精除低精 + 高精加高精过了。

代码

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 = 1010;
const ll B = 10000000000LL;

ll ans[maxn], a[maxn], ta[maxn], n;

void add(ll *a, ll &lena, ll *b, ll &lenb) {
	memset(ta, 0, sizeof(ta));
	ll nl = min(max(lena, lenb), 10LL);
	for (int i = 0; i < nl; ++i) {
		ta[i] = a[i] + b[i];
	}
	for (int i = 0; i < nl; ++i) {
		if (ta[i] >= B) {
			ta[i + 1] += ta[i] / B;
			ta[i] %= B;
		}
	}
	while (ta[nl]) {
		++nl;
	}
	memcpy(a, ta, sizeof(ta));
	lena = nl;
}

void mul(ll *a, ll &lena, ll b) {
	memset(ta, 0, sizeof(ta));
	ll nl = lena;
	for (int i = 0; i < nl; ++i) {
		ta[i] = a[i] * b;
	}
	for (int i = 0; i < nl; ++i) {
		if (ta[i] >= B) {
			ta[i + 1] += ta[i] / B;
			ta[i] %= B;
		}
	}
	while (ta[nl]) {
		ta[nl + 1] += ta[nl] / B;
		ta[nl] %= B;
		++nl;
	}
	memcpy(a, ta, sizeof(ta));
	lena = nl;
}

void div(ll *a, ll &lena, ll b) {
	memset(ta, 0, sizeof(ta));
	ll nl = lena, rem = 0;
	for (int i = nl - 1; ~i; --i) {
		ta[i] = (rem * B + a[i]) / b;
		rem = (rem * B + a[i]) % b;
	}
	while (!ta[nl - 1]) {
		--nl;
	}
	memcpy(a, ta, sizeof(ta));
	lena = nl;
}

void solve() {
	memset(ans, 0, sizeof(ans));
	memset(a, 0, sizeof(a));
	ll lena = 1, lenb = 1;
	a[0] = ans[0] = 1;
	for (int i = 1; i <= n / 2; ++i) {
		mul(a, lenb, (n - 2 * i + 1) * (n - 2 * i + 2));
		div(a, lenb, i * (i + 1));
		add(ans, lena, a, lenb);
	}
	bool flag = 1;
	for (int i = min(lena - 1, 9LL); ~i; --i) {
		if (ans[i]) {
			if (flag) {
				printf("%lld", ans[i]);
				flag = 0;
			} else {
				printf("%010lld", ans[i]);
			}
		}
	}
	putchar('\n');
}

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

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