【YBTOJ】【Luogu P2480】[SDOI2010]古代猪文

题目链接:

链接

题目大意:

求:

[m^{sum_{d|n}C_{n}^{d}}mod 999911659 ]

正文:

这种指数一坨式子外面还套个模的一般考虑欧拉定理的推论或扩展欧拉定理。这个用扩展欧拉定理明显搞不了,就考虑用欧拉定理的推论。

[m^{sum_{d|n}C_{n}^{d}}equiv m^{sum_{d|n}C_{n}^{d}mod999911658}pmod{999911659} ]

还是难搞啊这指数一坨。但是我们发现里面有个组合数,这提示了我们可以 Lucas 定理优化,但是这里面的这个模数这么大一坨,还不如不用,所以考虑拆这个模数。在尝试的过程中你可能会试着将 (999911658) 分解质因数,分成了 (2,3,4679,35617) 四个质数。这么小,这么少,满足了我们利用 Lucas。但是怎么将它们重新拼起来才是关键。因为只有四个,很少,所以可以考虑用中国剩余定理:

[left{egin{matrix} xequiv a_1&quadpmod{2}\ xequiv a_2&quadpmod{3}\ xequiv a_3&quadpmod{4679}\ xequiv a_4&quadpmod{35617} end{matrix} ight.]

其中 (a_i) 就是要利用 Lucas 求出来的 (sum_{d|n}C_{n}^{d}) 模各质数得到的数。那么最后我们通过 CRT 求得 (x),代入回原式: (m^x)

代码:

ll M = 999911659ll, ans;
ll m_[5] = {0, 2ll, 3ll, 4679ll, 35617ll}, a[5];
ll prod[N];

void init(ll p)
{
	prod[0] = 1;
	for (register int i = 1; i <= p + 10; i++)
		prod[i] = (prod[i - 1] * i) % p;
}

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

ll qpow(ll a, ll b, ll p)
{
    a %= p;
	ll ans = 1;
	for(; b; b >>= 1, a = a * a % p)
		if(b & 1)
			ans = ans * a % p;
    return ans;
}
ll C(ll n, ll m, ll p)
{
    if(m > n)return 0;
    if(n == 0) return 1;
    return ((prod[n] * qpow(prod[m], p - 2, p)) % p * qpow(prod[n - m], p - 2, p) % p);
}

ll Lucas(ll n, ll m, ll p)
{
	if(!m) return 1;
	return C(n % p, m % p, p) * Lucas(n / p, m / p, p) % p;
}

int main()
{
	scanf ("%d%d", &n, &m);
	if (m % M == 0) {puts("0"); return 0;}    // 特判 m 是 999911659 因数
	for (int i = 1; i <= 4; i++)
	{
		init(m_[i]);
		for (int j = 1; j * j <= n; j++)
		{
			if(n % j) continue;
			(a[i] += Lucas(n, j, m_[i])) %= m_[i];
			if(j * j == n) continue;
			(a[i] += Lucas(n, n / j, m_[i])) %= m_[i];
		}
	}
	for (int i = 1; i <= 4; i++)
	{
		ll t = 0, y; 
		exgcd(M / m_[i], m_[i], t, y);
		ans += a[i] * (M / m_[i]) * (t < 0? t + m_[i]: t);
	}
	printf("%lld", qpow(m, ans, M));
    return 0;
}
原文地址:https://www.cnblogs.com/GJY-JURUO/p/14117416.html