学期
Description
长度为 \(n\) 的序列, \(1/2\)个-1 , \(1/2\)个+1 ,问存在一个前缀值\(-k\)的方案数有多少.
Solution
K=1显然是Catalan数, 考虑Catalan数的证明过程
若数列不合法,则一定存在一个位置x,在这之前有m个+1,m + k个-1.
我们把之后的1变为-1,-1变为1.
这个东西好像叫反射
则该序列含有N + K个-1, N个1
方案数为\(2n\choose n + k\)
用总的\(2n\choose n\)减去即可.
因为错误的公式挂了40分.
Code
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
const int N = 1005;
const int M = 2e6 + 5;
long long mod;
int f[N << 1][N];
int pri[M], tot;
bool mr[M];
void Generate() {
mr[1] = 1;
for (int i = 2; i < M; i += 1) {
if (not mr[i])
pri[++tot] = i;
for (int j = 1; j <= tot and i * pri[j] < M; j += 1) {
mr[i * pri[j]] = true;
if (i % pri[j] == 0) break;
}
}
}
inline long long Pow(long long a, long long b) {
long long res = 1, base = a;
while (b) {
if (b & 1) res = res * base % mod;
base = base * base % mod;
b >>= 1;
}
return res;
}
inline long long Fen(int n, int p) {
long long res = 0;
while (n) { res += n / p, n /= p; }
return res;
}
long long Fenjie(int n, int k) {
long long A = 1, B = 1;
long long p;
for (int i = 1; i <= tot; i += 1) {
p = Fen(2 * n, pri[i]);
if (not p) continue;
A = A * Pow(pri[i], p - 2ll * Fen(n, pri[i])) % mod;
B = B * Pow(pri[i], p - Fen(n + k, pri[i]) - Fen(n - k, pri[i])) % mod;
}
return ((A - B) % mod + mod) % mod;
}
int main () {
Generate();
int n, k;
scanf("%d%d%d", &n, &k, &mod);
if (n > 1000) {
printf("%I64d\n", Fenjie(n, k));
return 0;
}
int nn = n << 1;
f[0][0] = 1;
for (int i = 1; i <= nn; i += 1)
for (int j = 0; j <= std:: min(i, n); j += 1) {
if (i - 2 * j >= k) continue;
f[i][j] = (f[i - 1][j] + (j ? f[i - 1][j - 1] : 0)) % mod;
}
printf("%d\n", f[nn][n]);
return 0;
}
为什么要过别人为我安排的生活.