CF896D

CF896D

说一下感觉有用的点:

1.对卡特兰数敏感一些,就是一些加减的操作,要保证每时每刻都为正。

2.对于组合数取模,模数非质数。

设模数为 \(\text{mod}\) ,将模数分解质因数,即:$ \text{mod} = P_{1}^{m_1} \cdot P_{2}^{m_2} \cdot… \cdot P_{cnt}^{m_{cnt}} $ , $ \text{cnt} $ 即模数的质因数个数。

对于组合数中阶乘的取模,预处理, \(1\backsim n\) 枚举要乘的数,记为 \(\text{res}\)

\(\text{res}\) 分解成 $\text{res} = P_{1}^{c_1} \cdot P_{2}^{c_2} \cdot… \cdot P_{cnt}^{c_{cnt}} \cdot x $ 的形式,这里的 \(P\) 是模数的质因子,可以发现 \(x\)\(\text{mod}\) 互质,根据欧拉定理:当 \(\gcd(a, b) = 1\)\(a^{phi_b}\equiv 1 \ (mod \ b)\) ,用快速幂可以求出 \(x\) 关于 \(mod\) 的逆元。

之后做一下分解数 的质因子的前缀和,因为只涉及到乘和除的操作,相当于是将这个数乘这些质因子再乘回去。

Code moo~~
using namespace std;
#define int long long
#define re register int
#define pc_ putchar(' ')
#define pc_n putchar('\n')
#define Bessie signed
const int CTR = 2e5 + 7;
int n, MOD, l, r;
int phi;
int qpow(int x, int y) {
    int base = 1;
    while(y) {
        if(y & 1) base = base * x % MOD;
        x = x * x % MOD;
        y >>= 1;
    }
    return base;
}
int p[CTR], cnt;
int zs[CTR][40];
int jc[CTR], inv[CTR];
void init() {
    int res = MOD;
    for(re i = 2; i * i <= res; ++i) {
        if(res % i) continue;
        p[++cnt] = i;
        while(!(res % i)) res /= i;
    }
    if(res != 1) p[++cnt] = res;
    jc[0] = inv[0] = jc[1] = inv[1] = 1;
    for(re i = 2, res; i <= n; ++i) {
        res = i;
        for(re j = 1; j <= cnt; ++j) {
            zs[i][j] = zs[i - 1][j];
            while(!(res % p[j])) {
                res /= p[j];
                ++zs[i][j];
            }
        }
        jc[i] = jc[i - 1] * res % MOD;
        inv[i] = qpow(jc[i], phi - 1);
    }
}
int C(int n, int m) {
    if(n < m) return 0;
    if(m == 0) return 1;
    int res = jc[n] * inv[m] % MOD * inv[n - m] % MOD;
    for(re i = 1; i <= cnt; ++i) (res *= qpow(p[i], zs[n][i] - zs[n - m][i] - zs[m][i])) %= MOD;
    return res;
}
int ans;
Bessie main() {
    n = read(), MOD = read(), l = read(), r = read();
    int res = MOD;
    phi = MOD;
    for(re i = 2; i * i <= MOD; ++i) {
        if(res % i) continue;
        phi = phi / i * (i - 1);
        while(!(res % i)) res /= i;
    }
    if(res != 1) phi = phi / res * (res - 1);
    init();
    for(re i = 0; i <= n; ++i) (ans += C(n, i) * ((C(i, ceil((double)(i + l) / 2))) - C(i, (i + r) / 2 + 1) % MOD + MOD) % MOD) %= MOD;
    ot(ans);
    return 0;
}

\[\bm{hzoi-Creator\_157} \]

posted @ 2022-10-08 21:50  Creator_157  阅读(45)  评论(0)    收藏  举报