题意
(n)个人,每个人可以站红队,可以站蓝队,也可以当观察者。
红队获胜当且仅当站红队的人数大于站蓝队的人数。
问红队获胜的方案数,对小质数(p)取模。
(n leq {10} ^ {18}, p leq {10} ^ {6})。
题解
列出式子:
[sum_{i = 0} ^ n inom{n}{i} sum_{j = 0} ^ {lfloor frac{n - i - 1}{2}
floor} inom{n - i}{j}
]
发现后面这个东西相当于
[sum_{i = 0} ^ n inom{n}{i} 2 ^ {n - i - 1} - sum_{i = 0} ^ n inom{n}{i} inom{n - i}{i}
]
即将红队非输的方案数减去红队平的方案数得到的结果。
发现上面的东西等于
[frac{1}{2} left(3 ^ n - sum_{i = 0} ^ n inom{n}{i} inom{n - i}{i}
ight)
]
右边这东西怎么算?
由于(p)比较小,而(n)比较大,不太方便处理阶乘,所以考虑用lucas定理。
考虑在(p)进制下,(n = {(n_1, n_2, ldots, n_k)}_p)。
我们要枚举一个(i = {(i_1, i_2, ldots, i_k)}_p),将(inom{n}{i} inom{n - i}{i})计入答案。
也即
[inom{n_1}{i_1} inom{n_2}{i_2} ldots inom{n_k}{i_k} inom{{(n - i)}_1}{i_1} inom{{(n - i)}_2}{i_2} ldots inom{{(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),那么(inom{n_w}{i_w})就为0了。
那么我们可以对于总共(k)位,计算(prod_{w = 1} ^ {k} sum_{i = 0} ^ {p - 1} inom{n_w}{i} inom{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;
}