哇,太恶心了
思路
首先我们将题意简化,简化后为对于任意一个偶数位所填数必然大于等于自己的下标,那么考虑填数,如果填的偶数比奇数多,那么此时要么填尽偶数后失败,或者下一个位置填奇数就炸,比如偶数刚好多一个,那么必然有一个偶数放在了奇数位,那么本来下一个要填的偶数往前移了一个,导致接下来只能继续填偶数,然后就失败了,所以我们的到结论,任何时候都要保证偶数个数比奇数个数少,所以可以将其转化为卡特兰数,然后一看数据 \(p\) 可为合数,直接寄
code
#include <iostream>
using namespace std;
const int MaxN = 2e6 + 10;
struct math {
int qpow(int a, int b, int p) {
int res = 1;
for (int i = 1; i <= b; i <<= 1) {
(b & i) && (res = 1ll * res * a % p);
a = 1ll * a * a % p;
}
return res;
}
int exgcd(int a, int b, int &x, int &y) {
if (!b) return x = 1, y = 0, a;
int g = exgcd(b, a % b, y, x);
return y = (y - (a / b * x)), g;
}
int inv(int x, int p) {
int b, y;
exgcd(x, p, b, y);
return (b % p + p) % p;
}
int f(int x, int p, int mod) {
if (!x) return 1;
int res = 1;
for (int i = 1; i <= mod; i++) {
(i % p) && (res = 1ll * res * i % mod);
}
res = qpow(res, x / mod, mod);
for (int i = 1; i <= x % mod; i++) {
(i % p) && (res = 1ll * res * i % mod);
}
return 1ll * res * f(x / p, p, mod) % mod;
}
int CRT(int k, int a[], int r[]) {
int n = 1, res = 0;
for (int i = 1; i <= k; i++) n *= r[i];
for (int i = 1; i <= k; i++) {
int m = n / r[i];
res = (res + 1ll * a[i] * m % n * inv(m, r[i]) % n) % n;
}
return res;
}
bool vis[MaxN];
int p[MaxN], tot;
void OLS() {
for (int i = 2; i < MaxN; i++) {
if (!vis[i]) p[++tot] = i;
for (int j = 1; j <= tot && 1ll * p[j] * i < MaxN; j++) {
vis[p[j] * i] = 1;
if (i % p[j] == 0) break;
}
}
}
int get_ans(int n, int m, int p, int mod) {
int cnt = 0;
for (int i = n; i; i /= p) cnt += i / p;
for (int i = m; i; i /= p) cnt -= i / p;
for (int i = n - m; i; i /= p) cnt -= i / p;
return 1ll * qpow(p, cnt, mod) * f(n, p, mod) % mod * inv(f(m, p, mod), mod) % mod * inv(f(n - m, p, mod), mod) % mod;
}
int a[MaxN], cp[MaxN], mp[MaxN], ff[MaxN], cnt;
void breakdown(int mod) {
cnt = 0;
for (int i = 1; 1ll * p[i] * p[i] <= mod; i++) {
if (mod % p[i] == 0) {
for (mp[++cnt] = 1, cp[cnt] = p[i]; mod % p[i] == 0; mp[cnt] *= p[i], mod /= p[i]) {
}
}
}
(mod > 1) && (mp[++cnt] = mod, cp[cnt] = mod);
if (cnt == 1) {
for (int i = 1; i < MaxN; i++) {
ff[i] = 1ll * ff[i - 1] * i % mod;
}
}
}
int exLucas(int n, int m, int mod) {
if (n < m) return 0;
if (cnt == 1) { // 大质数去死吧!
return 1ll * ff[n] * qpow(ff[m], mod - 2, mod) % mod * qpow(ff[n - m], mod - 2, mod) % mod;
}
for (int i = 1; i <= cnt; i++) {
a[i] = get_ans(n, m, cp[i], mp[i]);
}
return CRT(cnt, a, mp);
}
math() {
OLS(), ff[0] = 1;
}
} st;
int n, mod;
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> mod;
st.breakdown(mod);
cout << ((st.exLucas(n + n, n, mod) - st.exLucas(n + n, n - 1, mod)) % mod + mod) % mod << '\n';
return 0;
}
标签:cnt,数列,奇数,int,偶数,ff,P3200,HNOI2009,mod
From: https://www.cnblogs.com/ybtarr/p/18345982