jzoj 6301. 普及组

Description

详见OJ

Solution

感觉这题是最神仙的。。。
考场(AC)的人说自己是暴力枚举转移方程而得到了一个正确的转移式。
对于数据中的(x),我们发现分解质因数后,每个质因数的指数最大是(2)

当指数为(1)的时候,很容易得出答案乘以(n!)(因为每列每行都只能有一个这个质数)
当指数为(2)的时候,那人通过暴枚得出(f[i]=i*i*f[i-1]+i*(i-1)*(i-1)/2*f[i-2]),答案乘以(f[n])
最后再乘以(2^{(n-1)*(n-1)})即可。

Code

#include <cstdio>
#define N 5000000
#define ll long long
#define mo 998244353
#define mem(x, a) memset(x, a, sizeof x)
#define fo(x, a, b) for (int x = a; x <= b; x++)
#define fd(x, a, b) for (int x = a; x >= b; x--)
using namespace std;
int T, n, cs[31][2], tot = 0;
ll x, f[N + 10], jc[N + 10], tot1 = 0, tot2 = 0;

inline int read()
{
	int x = 0; char c = getchar();
	while (c < '0' || c > '9') c = getchar();
	while (c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
	return x;
}

ll ksm(ll x, int y)
{
	ll s = 1;
	while (y)
	{
		if (y & 1) s = s * x % mo;
		x = x * x % mo; y >>= 1;
	}
	return s;
}

int main()
{
	freopen("pj.in", "r", stdin);
	freopen("pj.out", "w", stdout);
	scanf("%lld", &x);
	fo(i, 2, 3000)
		if (x % i == 0)
		{
//			cs[++tot][0] = i;
			tot = 0;
			while (x % i == 0)
				x /= i, tot++;
			if (tot == 1) tot1++;
			else tot2++;
		}
	if (x > 1) tot1++;
	f[1] = 1, f[2] = 3; jc[1] = 1, jc[2] = 2;
	for (ll i = 3; i <= N; i++)
	{
		f[i] = (i * i % mo * f[i - 1] % mo - i * (i - 1) / 2 % mo * (i - 1) % mo * f[i - 2] % mo + mo) % mo;
		jc[i] = jc[i - 1] * i % mo;
	}
	T = read();
	while (T--)
	{
		n = read();
		printf("%d
", ksm(jc[n], tot1) * ksm(f[n], tot2) % mo * ksm(2, (ll)(n - 1) * (n - 1) % (mo - 1)) % mo);
	}
	return 0;
}
转载需注明出处。
原文地址:https://www.cnblogs.com/jz929/p/11348962.html