luogu2480 [SDOI2010]古代猪文

link

题意一开始没TM读懂。。。

就是给定一个\(G\le10^{10},N\le10^9\),求\(G^{\sum_{d|n}{n\choose d}}\),对999911659取模

由于999911659是质数,所以上面的数可以对999911658取模

现在问题转化为求\(\sum_{d|n}{n\choose d}\)对999911658取模(然后加个快速幂就行了)

对999911658质因数分解,可得\(999911658=2*3*4679*35617\)

由于次数都是一次,所以对这些数进行卢卡斯定理,然后中国剩余定理合并即可

不错的一道题,综合了好几道数论题一起考

#include <cstdio>
#define int long long
using namespace std;

int g, n, d[2333], tot;
int p, fac[40010], inv[40010];

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

struct fuck
{
	int x, y;
	fuck(int x = 0, int y = 0) : x(x), y(y) {}
};

int qpow(int x, int y)
{
	int res = 1;
	for (x %= p; y > 0; x = x * x % p, y >>= 1) if (y & 1) res = res * x % p;
	return res;
}

int c(int n, int m)
{
	if (n < m || m < 0) return 0;
	if (n < p && m < p) return fac[n] * inv[m] % p * inv[n - m] % p;
	return c(n / p, m / p) * c(n % p, m % p) % p;
}

int work()
{
	int ans = 0;
	fac[0] = 1;
	for (int i = 1; i < p; i++) fac[i] = fac[i - 1] * i % p;
	inv[p - 1] = qpow(fac[p - 1], p - 2);
	for (int i = p - 1; i >= 1; i--) inv[i - 1] = inv[i] * i % p;
	for (int i = 1; i <= tot; i++)
		ans = (ans + c(n, d[i])) % p;
	return ans;
}

signed main()
{
	scanf("%lld%lld", &n, &g);
	if (g % 999911659 == 0)
	{
		printf("0\n");
		return 0;
	}
	for (int i = 1; i * i <= n; i++)
		if (n % i == 0)
		{
			d[++tot] = i;
			if (i * i != n) d[++tot] = n / i;
		}
	long long ans1, ans2, ans3, ans4;
	p = 2, ans1 = work();
	p = 3, ans2 = work();
	p = 4679, ans3 = work();
	p = 35617, ans4 = work();
	p = 999911659;
	printf("%lld\n", qpow(g, (499955829 * ans1 + 333303886 * ans2 + 289138806 * ans3 + 877424796 * ans4) % (p - 1)));
	return 0;
}

一开始全WA了一发,#define int long long后95pts,第13个点read1expect 0

后来观察讨论发现是需要判断g和999911659不互质并且指数和p-1不互质的情况了(就是g是999911659倍数情况)

或者就是说\((kp)^{z(p-1)}\)被模成了0^0,然后快速幂返回了1

posted @ 2019-01-22 14:49  ghj1222  阅读(129)  评论(0编辑  收藏  举报