[ural 2126]. Partition into Teams

题意

\(n\)个人,每个人可以站红队,可以站蓝队,也可以当观察者。
红队获胜当且仅当站红队的人数大于站蓝队的人数。
问红队获胜的方案数,对小质数\(p\)取模。
\(n \leq {10} ^ {18}, p \leq {10} ^ {6}\)

题解

列出式子:

\[\sum_{i = 0} ^ n \binom{n}{i} \sum_{j = 0} ^ {\lfloor \frac{n - i - 1}{2} \rfloor} \binom{n - i}{j} \]

发现后面这个东西相当于

\[\sum_{i = 0} ^ n \binom{n}{i} 2 ^ {n - i - 1} - \sum_{i = 0} ^ n \binom{n}{i} \binom{n - i}{i} \]

即将红队非输的方案数减去红队平的方案数得到的结果。
发现上面的东西等于

\[\frac{1}{2} \left(3 ^ n - \sum_{i = 0} ^ n \binom{n}{i} \binom{n - i}{i}\right) \]

右边这东西怎么算?
由于\(p\)比较小,而\(n\)比较大,不太方便处理阶乘,所以考虑用lucas定理。
考虑在\(p\)进制下,\(n = {(n_1, n_2, \ldots, n_k)}_p\)
我们要枚举一个\(i = {(i_1, i_2, \ldots, i_k)}_p\),将\(\binom{n}{i} \binom{n - i}{i}\)计入答案。
也即

\[\binom{n_1}{i_1} \binom{n_2}{i_2} \ldots \binom{n_k}{i_k} \binom{{(n - i)}_1}{i_1} \binom{{(n - i)}_2}{i_2} \ldots \binom{{(n - i)}_k}{i_k} \]

考虑到上面的式子当且仅当\(\forall_w, n_w = i_w + {(n - i)_w}\)时不为0。否则\(n_w + p = i_w + {(n - i)_w}\),则有\(n_w < i_w\),那么\(\binom{n_w}{i_w}\)就为0了。
那么我们可以对于总共\(k\)位,计算\(\prod_{w = 1} ^ {k} \sum_{i = 0} ^ {p - 1} \binom{n_w}{i} \binom{n_w - i}{i} [i \leq n_w][i \leq n_w - i]\)即可。
复杂度\(\mathcal O(p \log_p n)\)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 6, M = 64;
ll n, mod, ans, tmp;
ll fac[N], inv[N], a[M];
ll power (ll x, ll y) {
	ll ret = 1;
	for ( ; y; y >>= 1, x = x * x % mod) {
		if (y & 1) {
			ret = ret * x % mod;
		}
	}
	return ret;
}
void precalc () {
	fac[0] = 1;
	for (int i = 1; i < mod; ++i) {
		fac[i] = fac[i - 1] * i % mod;
	}
	inv[mod - 1] = power(fac[mod - 1], mod - 2);
	for (int i = mod - 2; ~i; --i) {
		inv[i] = inv[i + 1] * (i + 1) % mod;
	}
}
ll C (int n, int m) {
	return n < m || m < 0 ? 0 : fac[n] * inv[m] % mod * inv[n - m] % mod;
}
ll calc () {
	for ( ; n; n /= mod) {
		a[++a[0]] = n % mod;
	}
	ll ret = 1, tmp;
	for (int i = 1; i <= a[0]; ++i) {
		tmp = 0;
		for (int j = 0; j <= a[i] - j; ++j) {
			tmp = (tmp + C(a[i], j) * C(a[i] - j, j)) % mod;
		}
		ret = ret * tmp % mod;
	}
	return ret;
}
int main () {
	cin >> n >> mod, precalc();
	ans = (power(3, n) - calc() + mod) % mod;
	ans = ans * power(2, mod - 2) % mod;
	cout << ans << endl;
	return 0;
}
posted @ 2019-11-04 21:46  psimonw  阅读(244)  评论(0编辑  收藏  举报