新的数论宝宝

给定 \(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;
}

扩展欧拉定理
image


image


image
image
image


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


image
image


P7481 梦现时刻
image
image
image
image
image

点击查看代码
#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;
}

image
考虑当 \(m\) 变为 \(m + 1\) 时, 这个求和会增加一项 \(\binom{n}{m + 1}\),是可以 \(\mathcal O(n)\) 求的。
当 \(n\) 变为 \(n + 1\) 时,

\[\begin{align*} &\sum_{0\sim m}\binom{n + 1}{i}\\ =&\sum_{0\sim m}\left(\binom{n}{i}+\binom{n}{i-1}\right)\\ =&\sum_{0\sim m}\binom{n}{i} + \sum_{0\sim m-1}\binom{n}{i}\\ =&2\sum_{0\sim m}\binom{n}{i}-\binom{n}{m} \end{align*} \]

这个也是可以 \(\mathcal O(1)\) 变换的,所以我们直接莫队。


image
证明:
我们考虑在网格图上从 (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}\)。
因此答案就是

\[\binom{2n}{n}-\frac{n}{n+1}\binom{2n}{n}=\frac{\binom{2n}{n}}{n+1} \]

posted @ 2026-10-05 21:57  SigmaToT  阅读(8)  评论(0)    收藏  举报