洛谷 SP19148 / SPOJ INS14G Kill them All

洛谷传送门

SPOJ 传送门

比较经典的一道题。

思路

第一个怪物一定是 Digo 杀的,考虑第二个到最后一个怪物,如果忽略掉 Digo 杀的第一只怪物,那么每杀掉一只怪物后,Digo 的击杀数都不少于 Sharry 的击杀数。

假设现在在一个平面直角坐标系,位于点 \((0,0)\),Digo 杀一个怪物则向右上走一步,即 \((x,y) \to (x+1,y+1)\);Sharry 杀一个怪物则向右下走一步,即 \((x,y) \to (x+1,y-1)\)。则题要求的就是从 \((0,0)\)\(n - 1\) 步且任意时刻纵坐标 \(\ge 0\),即不越过或在直线 \(y = -1\) 上的方案数。

考虑枚举终点坐标 \((n-1,k)\),其中 \(0 \le k \le n-1\)\(2 \mid (n+k-1)\)。如果不考虑纵坐标 \(\ge 0\) 的限制,则从 \((0,0)\) 走到 \((n-1,k)\) 的方案数为 \(C_{n-1}^{\frac{n+k-1}{2}}\)。现在要减去不合法情况的方案数,设路径第一次与 \(y = -1\) 交于点 \((m,-1)\),将路径横坐标 \(\ge m\) 的部分沿 \(y = -1\) 翻折,则终点变为 \((n-1,-k-2)\)。因为从 \((0,0)\)\((n-1,-k-2)\) 一定要经过 \(y = -1\),所以不合法情况的方案数其实就是 \((0,0)\)\((n-1,-k-2)\) 的方案数,即 \(C_{n-1}^{\frac{n+k+1}{2}}\)

那么答案为

\[\sum\limits_{k=0}^{n-1} [2 \mid (n+k-1)]C_{n-1}^{\frac{n+k-1}{2}} - C_{n-1}^{\frac{n+k+1}{2}} \]

容易发现式子的项可以相互抵消,因此当 \(2 \mid n\) 时答案为 \(C_{n-1}^{\frac{n}{2}}\)\(2 \nmid n\) 时答案为 \(C_{n-1}^{\frac{n-1}{2}}\)

代码

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 = 1000100;
const int N = 1000000;
const ll mod = 1000000007;

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

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;
	}
}

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);
	if (n & 1) {
		printf("%lld\n", C(n - 1, (n - 1) / 2));
	} else {
		printf("%lld\n", C(n - 1, n / 2));
	}
}

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

posted @ 2022-07-20 16:43  zltzlt  阅读(48)  评论(0编辑  收藏  举报