新的数论宝宝
给定 \(n,k\),\(O(n)\) 求出 \(1\sim n\) 的所有数的 \(i^k\)。
因为 \(f(x) = i^k\) 也是一个积性函数。
我们考虑线性筛,只处理所有质数的快速幂。
因为质数个数是 \(O(\frac{n}{\ln n})\) 的,所以处理快速幂的复杂度是 \(O(n)\) 的。
点击查看代码
const int N = 5e7 + 10;
const int mod = 998244353;
int cnt_prime;
bool is_not_prime[N];
int prime[N];
int powk[N];
int get_pow(int x, int k)
{
int result = 1;
for (; k; x = 1ll * x * x % mod, k >>= 1)
{
if (k & 1)
result = 1ll * result * x % mod;
}
return result;
}
void get_powk(int n, int k)
{
powk[1] = 1;
for (int i = 2; i <= n; ++i)
{
if (!is_not_prime[i])
{
prime[++cnt_prime] = i;
powk[i] = get_pow(i, k);
}
for (int j = 1; j <= cnt_prime && i * prime[j] <= n; ++j)
{
is_not_prime[prime[j] * i] = true;
powk[prime[j] * i] = powk[prime[j]] * powk[i];
if (!(i % prime[j]))
break;
}
}
}
光速幂
我们对于一个固定的常数 \(c\),我们 \(q\) 次询问求 \(c\) 的 \(k\) 次幂模 \(p\),我们令 \(k = a\sqrt{p} + b\)。
于是我们预处理 \(c^{\sqrt{p}}\) 的 \(1\sim\sqrt{p}\) 次幂以及 \(c\) 的 \(1\sim \sqrt{p}\) 幂。
Binary_gcd
int get_gcd(int x, int y)
{
if (!x || !y)
return x | y;
int cnt_last_0_of_x = __builtin_ctz(x);
int cnt_last_0_of_y = __builtin_ctz(y);
int min_cnt = std::min(cnt_last_0_of_x, cnt_last_0_of_y);
y >>= cnt_last_0_of_y;
int tmp;
while (x)
{
x >>= cnt_last_0_of_x;
tmp = x - y;
cnt_last_0_of_x = __builtin_ctz(tmp);
y = std::min(x, y), x = abs(tmp);
}
return y << min_cnt;
}
扩展欧拉定理






你不妨令 \(g\) 为模 \(p\) 意义下的原根,令 \(a_x = g^{b_x},i = g^k\)。
则要 \((\sum b_x) \mod p = k\),用 bitset 优化 01背包 即可。


P7481 梦现时刻





点击查看代码
#include <iostream>
using std::cin;
using std::cout;
const int N = 5e3 + 10;
const int mod = 998244353;
int inv[N];
int f[N][N];
int main()
{
int n, m;
cin >> n >> m;
inv[1] = 1;
for (int i = 2; i <= m; ++i)
inv[i] = 1ll * (-mod / i + mod) * inv[mod % i] % mod;
for (int b = 0; b <= m; ++b)
{
int cna = 1;
int sm = 0;
for (int i = 0; i <= b; ++i)
{
sm = (sm + cna) % mod;
if (i != b)
cna = 1ll * cna * (b - i) % mod * inv[i + 1] % mod;
}
f[0][b] = sm;
}
for (int a = 1; a <= m; ++a)
{
int c = 1;
for (int j = 1; j <= a; ++j)
c = 1ll * c * (n - j + 1) % mod * inv[j] % mod;
f[a][0] = c;
}
int ans = 0;
for (int i = 1; i <= m; ++i)
{
for (int j = 1; j <= m; ++j)
{
f[i][j] = ((2ll * f[i][j - 1] - f[i - 1][j] + f[i - 1][j - 1]) % mod + mod) % mod;
ans ^= f[i][j];
}
}
cout << ans << '\n';
return 0;
}

考虑当 \(m\) 变为 \(m + 1\) 时, 这个求和会增加一项 \(\binom{n}{m + 1}\),是可以 \(\mathcal O(n)\) 求的。
当 \(n\) 变为 \(n + 1\) 时,
这个也是可以 \(\mathcal O(1)\) 变换的,所以我们直接莫队。

证明:
我们考虑在网格图上从 (0,0) 走到 (n,n),不能碰到 \(y=x+1\),的方案数。
我们考虑总的方案数 \(\binom{2n}{n}\) 减去不合法的方案数。
怎么求不合法的方案数?
我们考虑把 (0, 0) 沿 \(y=x+1\) 翻折到 (-1,1),则从新的起点走到 (n,n) 一定会碰到 \(y=x+1\),且我们把第一次碰到 \(y=x+1\) 之前的部分再翻折回去,这样的路径与不合法路径一一对应。
因此不合法路径数就是 \(\binom{2n}{n+1}=\frac{n}{n+1}\binom{2n}{n}\)。
因此答案就是

浙公网安备 33010602011771号