[题解] [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;
}
posted @ 2019-06-25 22:33  ztlztl  阅读(142)  评论(0编辑  收藏  举报