·首先理解一下题意, “给定正整数n,求n!的奇数因数个数占因数总数的分数”。
·所以,要把 n! 的因数全都找出来,我们考虑先分解质因数
·以 5! = 120 为例子 其分解质因数的结果为 120 = 23 * 31 * 51
·因为只有奇数 * 奇数 才会等于奇数 所以我们能知道 120 的奇数因数 只有可能为
1 (30 * 50) 、 3(31 * 50) 、 5(30 * 51)、 15(31 * 51)
·发现规律了吗?qwq 所以
(不知道怎么在牛客写Latex公式,就直接截图过来了(
·所以问题就转变为了如何求对应阶乘的2因数个数
·只要一直 /2 到 %2 不为0就行了(记得特判一下0 复杂度O(log(N!))
·现在好像只要预处理一遍阶乘就能过了?
·但是我注意到,对阶乘n!其必然有质因数本质是 (n-1)! 的质因数 * n 的质因数
·所以对 n! 的因数2个数, 也满足这个, 所以我们可以用前缀和预处理的 复杂度O(NlogN)
void init(int n)
{
S_bary[1] = 0; // 2的因数个数的前缀和
for (int i = 2; i <= n; i ++ )
{
int num = i;
int bary = 0, odd = 0;
while (num && num % 2 == 0) // 一致除到 %2 不为0
{
bary ++ ;
num /= 2;
}
S_bary[i] = (S_bary[i - 1] + bary) % mod; // 前缀和
}
}
然后最后是要输出 p * q-1 mod M 到考虑使用经典的乘法逆元
所以乘上qM-2即可这里因为(a1 + 1)-1 为答案,所以输出(a1 + 1)M - 2
用快速幂实现, 复杂度O(logM)
ll qmi(ll a, ll b)
{
ll res = 1;
while (b)
{
if (b & 1) res = res * a % mod;
a = a % mod * a % mod;
b >>= 1;
}
return res;
}
·总复杂度O(T(logN + logM)) 能过
·完整AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 1000010, mod = 998244353;
int nums[N];
ll S_bary[N];
void init(int n)
{
S_bary[1] = 0;
for (int i = 2; i <= n; i ++ )
{
int num = i;
int bary = 0, odd = 0;
while (num && num % 2 == 0)
{
bary ++ ;
num /= 2;
}
S_bary[i] = (S_bary[i - 1] + bary) % mod;
}
}
ll qmi(ll a, ll b)
{
ll res = 1;
while (b)
{
if (b & 1) res = res * a % mod;
a = a % mod * a % mod;
b >>= 1;
}
return res;
}
int main()
{
int T;
scanf("%d", &T);
int maxv = 0;
for (int i = 0; i < T; i ++ )
{
scanf("%d", &nums[i]);
if (maxv < nums[i]) maxv = nums[i];
}
init(maxv);
for (int i = 0; i < T; i ++ )
{
printf("%lld ", qmi(S_bary[nums[i]] + 1, mod - 2) % mod);
}
puts("");
return 0;
}
·孩子第一次写提解(,欢迎讨论和指出错误
·希望对大伙有所帮助qwq

京公网安备 11010502036488号