LG P2480 [SDOI2010] 古代猪文 Solution

Description

给定 n,gn,gn,g,定义 f(n)=∑k∣n(nk)f(n)=\sum\limits_{k\mid n}\binom{n}{k}f(n)=kn(kn),求 gf(n) mod 999911659g^{f(n)}\bmod 999911659gf(n)mod999911659 的值.

Limitations

1≤n,g≤1091\le n,g\le 10^91n,g109
1s,125MB1\text{s},125\text{MB}1s,125MB

Solution

首先,如果 g=999911659g=999911659g=999911659,直接特判掉输出 000.
接下来,根据欧拉定理,我们需要求 f(n) mod 999911658f(n)\bmod 999911658f(n)mod999911658.
虽然可以暴力枚举 n\sqrt nn 个因数求答案,但是 999911658∉P999911658\notin \mathbb{P}999911658/P,在求组合数时无法直接使用 Lucas 定理.

注意到 999911658=2×3×4679×35617999911658=2\times 3\times 4679\times 35617999911658=2×3×4679×35617,无平方因子.
现在我们就可以用 Lucas 分别求出 f(n)f(n)f(n) 模这四个数的结果 a1,a2,a3,a4a_1,a_2,a_3,a_4a1,a2,a3,a4,然后用 CRT 解如下方程:
{x≡a1(mod2)x≡a2(mod3)x≡a3(mod4679)x≡a4(mod35617) \begin{equation*} \begin{cases} x\equiv a_1 \pmod 2 \\ x\equiv a_2 \pmod 3 \\ x\equiv a_3 \pmod {4679} \\ x\equiv a_4 \pmod {35617} \end{cases} \end{equation*} xa1(mod2)xa2(mod3)xa3(mod4679)xa4(mod35617)

即可得到 f(n) mod 999911658f(n)\bmod 999911658f(n)mod999911658,再用一次快速幂即可求得答案.

Code

2.14KB,94ms,864KB  (C++20 with O2)2.14\text{KB},94\text{ms},864\text{KB}\;\texttt{(C++20 with O2)}2.14KB,94ms,864KB(C++20 with O2)

#include <bits/stdc++.h>
using namespace std;

using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
using ui128 = unsigned __int128;
using f4 = float;
using f8 = double;
using f16 = long double;

template<class T>
bool chmax(T &a, const T &b){
	if(a < b){ a = b; return true; }
	return false;
}

template<class T>
bool chmin(T &a, const T &b){
	if(a > b){ a = b; return true; }
	return false;
}

constexpr int P = 999911659;

inline int add(int a, int b, int mod) { return (a + b >= mod) ? (a + b - mod) : (a + b); }
inline int mul(int a, int b, int mod) { return 1LL * a * b % mod; }
inline int qpow(int a, int b, int mod) {
    int res = 1;
    for (; b; b >>= 1, a = mul(a, a, mod))
        if (b & 1) res = mul(res, a, mod);
    return res;
}

struct Lucas {
	int P;
	vector<int> fac, ifac;
	inline Lucas() {}
	
	inline void init(int p) {
		P = p;
        fac.resize(P);
        ifac.resize(P);
        
        fac[0] = 1;
        for (int i = 1; i < P; ++i) {
            fac[i] = mul(fac[i - 1], i, P);
        }
        
        ifac[P - 1] = qpow(fac[P - 1], P - 2, P);
        for (int i = P - 2; i >= 0; --i) {
            ifac[i] = mul(ifac[i + 1], i + 1, P);
        }
	}
	
	inline int comb(int n, int m) {
        if (m < 0 || m > n) return 0;
        return mul(fac[n], mul(ifac[m], ifac[n - m], P), P);
    }
    
    inline int lucas(int n, int m) {
        if (m == 0) return 1;
        return mul(comb(n % P, m % P), lucas(n / P, m / P), P);
    }
};

signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	
	int n, g; cin >> n >> g;
	if (g == P) {
		cout << 0;
		return 0;
	}
	
	array<Lucas, 4> L;
	L[0].init(2), L[1].init(3);
	L[2].init(4679), L[3].init(35617);
	
	array<int, 4> sum; sum.fill(0);
	for (int i = 1; i <= n / i; i++) 
		if (n % i == 0)
			for (int j = 0; j < 4; j++) {
				sum[j] = add(sum[j], L[j].lucas(n, i), L[j].P); 
				if (i != n / i) sum[j] = add(sum[j], L[j].lucas(n, n / i), L[j].P);
			}
	
	int ans = 0;
	for (int i = 0; i < 4; i++) {
		int M = (P - 1) / L[i].P, Minv = qpow(M, L[i].P - 2, L[i].P);
		ans = add(ans, mul(mul(M, Minv, P - 1), sum[i], P - 1), P - 1);
	}
	cout << qpow(g, ans, P);
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值