BZOJ 1951: [Sdoi2010]古代猪文

要求 \(g^{\sum \limits _{i|n}\binom{n}{i}}\)
欧拉降幂之后就变成求 \(\sum \limits_{i|n}\binom{n}{i} \bmod (M - 1)\)
\(M - 1\) 是个合数,当时对它进行质因数分解后发现它是四个质数的乘积,分别对四个质数进行Lucas定理求组合数,最后再CRT合并一下

#include 

const int mod[10] = {2, 3, 4679, 35617}, MOD = 999911659, M = 999911658;
int fac[10][36000], inv[10][36000];

int qp(int a, int b, int m = MOD) {
    int ans = 1;
    a %= m;
    for (; b; b >>= 1, a = 1LL * a * a % m) 
        if (b & 1)
            ans = 1LL * ans * a % m;
    return ans % m;
}

int C(int n, int m, int cur) {
    if (n < m) return 0;
    int MOD = mod[cur];
    return 1LL * fac[cur][n] * inv[cur][m] % MOD * inv[cur][n - m] % MOD;
}

int Lucas(int n, int m, int cur) {
    if (n < m) return 0;
    int MOD = mod[cur];
    return m ? 1LL * Lucas(n / MOD, m / MOD, cur) * C(n % MOD, m % MOD, cur) % MOD : 1;
}

int a[4];

int CRT() {
    int ans = 0;
    for (int i = 0; i < 4; i++) {
        int m = M / mod[i];
        int inv_m = qp(m, mod[i] - 2, mod[i]);
        (ans += 1LL * m * inv_m % M * a[i] % M) %= M;
    }
    return ans;
}

int main() {
    for (int i = 0; i < 4; i++) 
        for (int j = fac[i][0] = 1; j < mod[i]; j++)
            fac[i][j] = 1LL * fac[i][j - 1] * j % mod[i];
    for (int i = 0; i < 4; i++) {
        inv[i][mod[i] - 1] = qp(fac[i][mod[i] - 1], mod[i] - 2, mod[i]);
        for (int j = mod[i] - 2; j >= 0; j--)
            inv[i][j] = 1LL * inv[i][j + 1] * (j + 1) % mod[i];
    }
    int n, g;
    scanf("%d%d", &n, &g);
    if (g == MOD) {
        puts("0");
        return 0;
    }
    g %= MOD;
    for (int i = 1; i * i <= n; i++) {
        if (n % i) continue;
        int x = i;
        for (int j = 0; j < 4; j++)
            a[j] = (a[j] + Lucas(n, x, j)) % mod[j];
        if (i * i == n) continue;
        x = n / i;
        for (int j = 0; j < 4; j++)
            a[j] = (a[j] + Lucas(n, x, j)) % mod[j];
    }
    printf("%d\n", qp(g, CRT()));
    return 0;
}

你可能感兴趣的:(BZOJ 1951: [Sdoi2010]古代猪文)