其他分享
首页 > 其他分享> > [题解] [SDOI2010] 古代猪文

[题解] [SDOI2010] 古代猪文

作者:互联网

题面

题解

题目所求即为
\[ G ^ {\sum_{d | n}C_{n}^{d}} \bmod {999911659} \]
考虑到有这样一个式子
\[ a ^ b \equiv a ^ {b \bmod \varphi(p)} \pmod p \]
由于999911659是一个质数, 所以\(\varphi(999911659) = 999911658\), 所以原式就变为了
\[ G^{\sum_{d | n} C_n^d \bmod 999911568} \bmod 999911659 \]
左边的东西只要求出\(\sum_{d | n} C_n^d \bmod 999911568\)即可快速幂, 所以题目转化为求左式

我们发现\(999911568 = 2 * 3 * 4257 * 35617\), 恩, 组合数取模求和, 上\(exLucas\)板子即可

Code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#define itn int
#define reaD read
#define Mod 999911659
#define int long long
using namespace std;

int n, m, mod[4] = { 2, 3, 4679, 35617 }, inv[4][50005], jc[4][50005], r[4]; 

inline int read()
{
    int x = 0, w = 1; char c = getchar();
    while(c < '0' || c > '9') { if (c == '-') w = -1; c = getchar(); }
    while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
    return x * w;
}

int fpow(int x, int y)
{
    int res = 1;
    while(y)
    {
        if(y & 1) res = res * x % Mod;
        x = x * x % Mod;
        y >>= 1; 
    }
    return res; 
}

int exgcd(int a, int b, int &x, itn &y)
{
    if(!b) { x = 1; y = 0; return a; }
    int q = a / b, r = a % b, d = exgcd(b, r, y, x);
    y -= q * x; return d; 
}

itn C(int n, int m, int opt)
{
    if(m > n) return 0; if(m > n - m) m = n - m; 
    return 1ll * jc[opt][n] * inv[opt][m] % mod[opt] * inv[opt][(n - m)] % mod[opt]; 
}

int lucas(int n, int m, int opt)
{
    if(!m) return 1; 
    return 1ll * C(n % mod[opt], m % mod[opt], opt) * lucas(n / mod[opt], m / mod[opt], opt) % mod[opt]; 
}

int excrt()
{
    int p1 = mod[0], r1 = r[0]; 
    for(int j = 1; j < 4; j++)
    {
        int p2 = mod[j], r2 = r[j], x, y, d = exgcd(p1, p2, x, y); 
        x *= (r2 - r1) / d; p2 /= d; x = (x % p2 + p2) % p2;
        r1 = p1 * x + r1; p1 = p1 * p2; 
    }
    return r1; 
}

int exlucas()
{
    for(int i = 1; i * i <= n; i++)
        if(n % i == 0)
        {
            if(i * i == n) for(int j = 0; j < 4; j++) r[j] = 1ll * (r[j] + lucas(n, i, j)) % mod[j];
            else for(int j = 0; j < 4; j++) r[j] = 1ll * (r[j] + lucas(n, i, j) + lucas(n, n / i, j)) % mod[j]; 
        }
    return excrt(); 
}

signed main()
{
    n = read(); m = read();
    if(m % 999911659 == 0) { puts("0"); return 0; }
    for(int i = 0; i <= 3; i++)
    {
        inv[i][0] = inv[i][1] = 1; jc[i][0] = jc[i][1] = 1; 
        for(int j = 2; j < mod[i]; j++) inv[i][j] = 1ll * (mod[i] - mod[i] / j) * inv[i][mod[i] % j] % mod[i];
        for(int j = 2; j < mod[i]; j++) inv[i][j] = 1ll * inv[i][j - 1] * inv[i][j] % mod[i]; 
        for(int j = 2; j < mod[i]; j++) jc[i][j] = 1ll * jc[i][j - 1] * j % mod[i]; 
    }
    printf("%lld\n", fpow(m, exlucas())); 
    return 0;
}

标签:opt,p2,include,return,int,题解,SDOI2010,猪文,mod
来源: https://www.cnblogs.com/ztlztl/p/11087137.html