ACWING 213 古代猪文

https://www.acwing.com/problem/content/215/

题意

给定整数 q , n ( 1 ≤ q , n ≤ 1 0 9 ) q,n(1 \leq q,n \leq 10^9) q,n(1q,n109),计算

q ∑ d ∣ n C n d m o d 999911659 q^{\sum_{d|n} C_n^d}mod 999911659 qdnCndmod999911659

思路

首先,进行一个特判。当 q = 999911659 q=999911659 q=999911659,显然答案为0。
否则由于999911659是一个质数,故其与q互质,满足欧拉定理的条件。
之后,由欧拉定理的推论

若正整数 a , n a,n a,n互质,则对于任意整数 a a a,有 a b ≡ a ( b    m o d    φ ( n ) ) ( m o d    n ) a^b \equiv a^{(b \; mod \; \varphi(n))}(mod \; n) aba(bmodφ(n))(modn)

可以得到

q ∑ d ∣ n C n d ≡ q ∑ d ∣ n C n d m o d    999911658 ( m o d    999911659 ) q^{\sum_{d|n}C_n^d} \equiv {q^{\sum_{d|n}C_n^d mod \; 999911658}}(mod \; 999911659) qdnCndqdnCndmod999911658(mod999911659)

注意到999911658显然是一个合数,我们尝试将它分解质因数得到

999911658 = 2 × 3 × 4679 × 35617 999911658=2 \times 3 \times 4679 \times 35617 999911658=2×3×4679×35617

它们的次数全都是1。


接下来,由于问题要求我们求 d ∣ n d|n dn,因此我们可以根据这些质因数枚举999911658的约数。对每一个约数,可以利用Lucas定理

C n m ≡ C n    m o d    p m    m o d    p ∗ C n p m p ( m o d    p ) C_n^m \equiv C_{n \; mod \; p}^{m \; mod \; p}* C_{\frac{n}{p}}^{\frac{m}{p}}(mod \; p) CnmCnmodpmmodpCpnpm(modp)

求出组合数 C n d C_n^d Cnd,并计算出 ∑ d ∣ n C n d \sum d|n C_n^d dnCnd对四个质因数取模的结果,记为 a 1 ∼ a 4 a_1 \sim a_4 a1a4


最后,利用中国剩余定理

m 1 ∼ m n m_1 \sim m_n m1mn是两两互质的整数, m = ∏ i = 1 n m i , M i = m m i m = \prod _{i=1}^nm_i,M_i=\frac{m}{m_i} m=i=1nmi,Mi=mim t i t_i ti是线性同余方程 M i t i ≡ 1 ( m o d    m i ) M_it_i \equiv 1(mod \; m_i) Miti1(modmi)。对于任意的 n n n个整数 a 1 ∼ a n a_1 \sim a_n a1an,方程组

{ x ≡ a 1 ( m o d    m 1 ) x ≡ a 2 ( m o d    m 2 ) … x ≡ a n ( m o d    m n ) \begin{cases} x \equiv a_1(mod \; m_1)\\ x \equiv a_2(mod \; m_2)\\ \dots\\ x \equiv a_n(mod \; m_n) \end{cases} xa1(modm1)xa2(modm2)xan(modmn)

有整数解为 x = ∑ i = 1 n a i M i t i x=\sum_{i=1}^{n}a_iM_it_i x=i=1naiMiti


解出线性方程组

{ x    m o d    2    =    a 1 x    m o d    3    =    a 2 x    m o d    4679    =    a 3 x    m o d    35617    =    a 4 \begin{cases} x \; mod \; 2 \; = \; a_1 \\ x \; mod \; 3 \; = \; a_2 \\ x \; mod \; 4679 \; = \; a_3 \\ x \; mod \; 35617 \; = \; a_4 \end{cases} xmod2=a1xmod3=a2xmod4679=a3xmod35617=a4

  • 这一步是可以转化成CRT的目标形式,即 x    ≡    a i ( m o d    m i ) x \; \equiv \; a_i(mod \; m_i) xai(modmi)的。这是因为 x    m o d    m i = a i x \; mod \; m_i = a_i xmodmi=ai代表 a i    m o d    m i ≡    a i a_i \; mod \; m_i \equiv \; a_i aimodmiai,又 x    m o d    m i = a i x \; mod \; m_i=a_i xmodmi=ai

得到 ∑ d ∣ n C n d m o d    999911658 \sum _{d|n}^{C_n^d} mod \; 999911658 dnCndmod999911658的最小非负整数解 x x x,然后利用快速幂求 q x q^x qx即可。

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int a[4] = {2, 3, 4679, 35617};
int factorials[36000], b[4], n, g, ans, x, y, mod = 999911658; // b中存储了CRT右侧的数字

int power(int a, int b)
{
    int res = 1;
    while (b)
    {
        if (b & 1)
            res = (ll)res * a % mod;
        b >>= 1;
        a = (ll)a * a % mod;
    }
    return res;
}

void exgcd(int a, int b, int &x, int &y)
{
    if (!b)
    {
        x = 1, y = 0;
        return;
    }
    exgcd(b, a % b, x, y);
    int z = x;
    x = y;
    y = z - y * (a / b);
}

int inv(int a, int p) // 求逆元
{
    int x, y;
    exgcd(a, p, x, y);
    return (x % p + p) % p;
}

int calc(int x, int mod) // lucas定理求组合数
{
    int ans = 1, y, a, b;
    for (y = n; x; x /= mod, y /= mod)
    {
        a = x % mod, b = y % mod;                                                                                            // 余数
        ans = (ll)ans * factorials[b] % mod * inv(factorials[a], mod) % mod * inv(b < a ? 0 : factorials[b - a], mod) % mod; // 求m!/n!(m-n)!
    }
    return ans;
}

int main()
{
    cin >> n >> g;
    g %= mod + 1;
    if (!g)
    { // 特判999911659
        cout << 0 << endl;
        return 0;
    }
    for (int i = factorials[0] = 1; i <= a[3]; i++)
    {
        // 阶乘预处理
        factorials[i] = (ll)factorials[i - 1] * i % mod;
    }
    for (int i = 1; i * i <= n; i++) // 枚举质因数可构成的约数
    {
        if (n % i == 0) // i是约数
        {
            for (int j = 0; j < 4; j++)
                b[j] = (b[j] + calc(i, a[j])) % a[j]; // 求C_n^i
            if (i * i != n)
            {
                for (int j = 0; j < 4; j++)
                    b[j] = (b[j] + calc(n / i, a[j])) % a[j]; // 枚举约数 并计算相应的组合数
            }
        }
    }
    for (int i = 0; i < 4; i++)
    {
        exgcd(mod / a[i], a[i], x, y); // CRT
        ans = (ans + (ll)x * (mod / a[i]) % mod * b[i]) % mod;
    }
    ans = (ans + mod) % mod, mod++; // 映射到最小非负值
    ans = power(g, ans);            // q^x
    cout << ans << endl;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值