// // // // // // // // // // // // // //

数学基础 3

数学基础 3

前言

想了一下 前面那个还是太多了 所以还是再开一个比较好


写不动了 受限于个人水平 后面的写不下去了 所以跑去搞别的(

根本学不会

指数方程

形如: \(a^x \equiv b \mod m\) 的方程

求解: BSGS​ (半死龟速算法)

可以在 \(O(\sqrt m)\) 的时间内求解 \(a^x \equiv b \mod m\) 要求 \(a \bot m\) 不一定要求 \(m\) 为素数

设定一个常量 \(T\) 使 \(x = qT - r\) 其中 \(0 \leq r < T\) 则原方程可以转化:

\(a^{qT - r} \equiv b \mod m \\ a^{qT} \equiv a^rb \mod m\)

考虑预处理所有的 \(a^rb \mod m\) 的值 用 \(hash\) 或者是 \(map\) 存起来 求解时枚举 \(q\) 计算 \(a^{qT}\) 判断哈希表或者 \(map\) 中是否出现了 \(a^{qT}\) 出现则说明等式成立 方程有解

预处理枚举至多 \(T\)\(r\) 复杂度 \(O(T)\) 查询时至多 \(\frac nT\)\(a^{qT} \mod m\) 复杂度 \(O(\frac mT)\) 总复杂度 \(O(\frac mT + T)\)\(T = \sqrt m\) 时达到平衡 复杂度 \(O(\sqrt m)\)

题目: BSGS

代码

/*
  Time: 6.20
  Worker: Blank_space
  Source: P3846 【模板】BSGS
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cmath>
#include<map>
#define int long long
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
inline void File() {
	freopen(".in", "r", stdin);
	freopen(".out", "w", stdout);
}
/*----------------------------------------文件*/
int b, p, n, T;
std::map <int, int> mp;
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/
int power(int _a, int _b, int res = 1) {for(; _b; _a = _a * _a % p, _b >>= 1) if(_b & 1) res = res * _a % p; return res;}
void BS() {
	T = ceil(sqrt(p)) + 1; int sum = n;
	for(int r = 0; r < T; r++) mp[sum] = r, sum = sum * b % p;
}
bool GS() {
	int bt = power(b, T), sum = bt;
	for(int q = 1; q <= T; q++)
	{
		if(mp.count(sum)) {printf("%lld", q * T - mp[sum]); return 1;}
		sum = sum * bt % p;
	}
	return 0;
}
/*----------------------------------------函数*/
signed main() {
	p = read(); b = read(); n = read();
	if(!(b % p)) {puts("no solution"); return 0;}
	BS(); if(!GS()) puts("no solution");
	return 0;
}

**扩展BSGS **

仍是求解 \(a^x \equiv b \mod m\) 但是不保证 \(a \bot m\)

由于阶和原根没学的原因 OI-wike 上的没有看懂...

考虑将上面那个转换为一般的 BSGS

\(d_1 = (a, m)\)\(d_1 \nmid b\) 则原方程无解 否则令方程两边同除 \(d_1\) 得:\(\frac a{d_1} \times a^{x - 1} \equiv \frac b{d_1} \mod \frac m{d_1}\)\((a, \frac m{d_1}) \ne 1\)\(d_2 = (a, \frac m{d_1})\) 重复上述步骤 知道 \((a, \frac m{\prod_{i = 1}^kd_k}) = 1\) 为止

此时方程为: \(\frac {a^k}{\prod_{i = 1}^kd_k} \times a^{x - k} \equiv \frac b{\prod_{i = 1}^kd_k} \mod \frac {m}{\prod_{i = 1}^kd_k}\)

然后按照 BSGS 来搞就好了 枚举 \(a^{qT}\) 的时候乘上常数 \(\frac {a^k}{\prod_{i = 1}^kd_k}\) 即可

注意枚举 \(k\) 的时候判断 \(a^{x - k} \equiv b \mod m\) 是否存在 注意保证指数不为负数

题目: 扩展BSGS

这个题的原题是卡 \(map\) 的 但是在这个数据比较弱的模板题上 \(map\) 是能过的

代码

/*
  Time: 6.20
  Worker: Blank_space
  Source: P4195 【模板】扩展BSGS
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cmath>
#include<map>
#define int long long
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
inline void File() {
	freopen(".in", "r", stdin);
	freopen(".out", "w", stdout);
}
/*----------------------------------------文件*/
int a, b, p, T, d;
std::map <int, int> mp;
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/
int power(int _a, int _b, int res = 1) {for(; _b; _a = _a * _a % p, _b >>= 1) if(_b & 1) res = res * _a % p; return res;}
int gcd(int _a, int _b) {return _b ? gcd(_b, _a % _b) : _a;}
int BSGS(int ad) {
	mp.clear();
	T = ceil(sqrt(p)) + 1; int sum = b % p;
	for(int r = 0; r < T; r++) mp[sum] = r, sum = sum * a % p;
	int at = power(a, T); sum = ad;
	for(int q = 0; q <= T; q++)
	{
		if(mp.count(sum) && q * T - mp[sum] >= 0ll) return q * T - mp[sum];
		sum = sum * at % p;
	}
	return -1;
}
int exBSGS() {
	a %= p; b %= p; if(b == 1 || p == 1) return 0;
	int k = 0, d, ad = 1;
	while((d = gcd(a, p)) != 1)
	{
		if(b % d) return -1;
		k++; b /= d; p /= d; ad = ad * a / d % p;
		if(ad == b) return k;
	}
	int ans = BSGS(ad);
	return ~ans ? BSGS(ad) + k : -1;
}
/*----------------------------------------函数*/
signed main() {
	while(1)
	{
		a = read(); p = read(); b = read();
		if(!a && !p && !b) return 0;
		int ans = exBSGS();
		if(~ans) printf("%lld\n", ans); else puts("No Solution");
	}
	return 0;
}

计算器

任务一直接快速幂即可

任务二扩展欧几里得

任务三 BSGS 即可

有一点需要注意

一般来说 在 \(a^x \equiv b \mod p\) 中 当 \(b \mid p\) 的时候是无解的 但是如果 \(a \mid p, b \mid p\) 同时成立的话 方程是有解的 最小整数解为 \(x = 1\) 需要判断 否则最后一个点过不去

代码

/*
  Time: 6.20
  Worker: Blank_space
  Source: P2485 [SDOI2011]计算器
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cmath>
#include<map>
#define int long long
/*--------------------------------------头文件*/
int _T, T, k, x, y, p, d, a, b;
std::map <int, int> mp;
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/
int power(int _a, int _b, int res = 1) {for(; _b; _a = _a * _a % p, _b >>= 1) if(_b & 1) res = res * _a % p; return res;}
void exgcd(int _a, int _b, int &_d, int &_x, int &_y) {
	if(_b) exgcd(_b, _a % _b, _d, _y, _x), _y -= _x * (_a / _b);
	else _d = _a, _x = 1, _y = 0;
}
void work1() {printf("%lld\n", power(a, b));}
void work2() {
	a %= p; b %= p;
	if(!b) {puts("0"); return ;}
	exgcd(a, p, d, x, y); x = x * b / d;
	if(b % d) {puts("Orz, I cannot find x!"); return ;}
	printf("%lld\n", (x % p + p) % p);
}
void BS() {
	mp.clear(); T = ceil(sqrt(p)) + 1; int sum = b % p;
	for(int r = 0; r < T; r++) mp[sum] = r, sum = sum * a % p;
}
bool GS() {
	int at = power(a, T), sum = at;
	for(int q = 1; q <= T; q++)
	{
		if(mp.count(sum)) {printf("%lld\n", q * T - mp[sum]); return 1;}
		sum = sum * at % p;
	}
	return 0;
}
void work3() {
	if(b % p == 1) {puts("0"); return ;}
	if(!(a % p) && !(b % p)) {puts("1"); return ;}
	if(!(a % p)) {puts("Orz, I cannot find x!"); return ;}
	BS(); if(!GS()) puts("Orz, I cannot find x!");
}
void work() {
	a = read(); b = read(); p = read();
	if(k == 1) work1();
	if(k == 2) work2();
	if(k == 3) work3();
}
/*----------------------------------------函数*/
signed main() {
	_T = read(); k = read(); while(_T--) work();
	return 0;
}

随机数生成器

题意简述

给定 \(p, a, b, x_1, t\) 已知 \(x_i \equiv a \times x_{i - 1} + b \mod p\)\(i_{min}\) 使 \(x_i = t\) 成立

写一下递推式

\(x_1 = x_1 \\ x_2 = ax_1 + b \\ x_3 = a^2x_1 + ab + b \\ x_4 = a^3x_1 + a^2b + ab + b \\ ...\)

不难得出 \(x_i = a^{i - 1}x_1 + \sum_{j = 0}^{i - 2}a^jb\)

后面那一坨是等比数列的形式 再化一下 有 \(x_i = a^{i - 1}x_1 + \frac {b(a^{i - 1} - 1)}{a - 1}\)

继续搞

\(x_i \equiv a^{i - 1}x_1 + \frac {b(a^{i - 1} - 1)}{a - 1} \\ x_i(a - 1) \equiv a^{i - 1}(a - 1)x_1 + b(a^{i - 1} - 1) \\ ax_i - x_i \equiv a^{i - 1}(ax_1 - x_1) + a^{i - 1}b - b \\ ax_i - x_i + b \equiv a^{i - 1}(ax_1 - x_1) + a^{a - 1}b \\ ax_i - x_i + b \equiv a^{i - 1}(ax_1 - x_1 + b) \\ a^{i - 1} \equiv \frac {ax_i - x_i + b}{ax_1 - x_1 + b}\)

我们的目的是求 \(i\) 使 \(t = x_i\)

直接将 \(t\) 代入 有 \(a^{i - 1} \equiv \frac {at - t + b}{ax_1 - x_1 + b}\)

可以发现这是一个长得比较 BSGS 的式子

跑一下 答案加一即可

细节比较多

首先是当输入的 \(x_1\) 直接等于 \(t\) 的时候 直接输出 \(1\)

\(a = 1\) 的时候 原来的递推式变成了一个等差数列 不难推出 \(x_i = x_1 + (i - 1)b\) 代入 \(t\) 移项 得 \(i - 1 = \frac {t - x_1}b\) 判一下 \(b\) 是否为 \(0\) 输出即可

\(a = 0\) 的时候 上式为 \(0 \equiv \frac {b - t}{b - t}\)\(b = t\) 时是有解的 但解是多少 回到原来的递推中 不难发现 当 \(i > 1\) 的时候 所有项都为常量 \(b\) 答案即为 \(2\)

代码

/*
  Time: 6.20
  Worker: Blank_space
  Source: P3306 [SDOI2013] 随机数生成器
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cmath>
#include<map>
#define int long long
/*--------------------------------------头文件*/
inline void File() {
	freopen(".in", "r", stdin);
	freopen(".out", "w", stdout);
}
/*----------------------------------------文件*/
int p, a, b, x, t, T, _T, k;
std::map <int, int> mp;
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/
int power(int _a, int _b, int res = 1) {for(; _b; _a = _a * _a % p, _b >>= 1) if(_b & 1) res = res * _a % p; return res;}
void BS() {
	mp.clear(); T = ceil(sqrt(p)) + 1; int sum = k;
	for(int r = 0; r < T; r++) mp[sum] = r, sum = sum * a % p;
}
bool GS() {
	int at = power(a, T), sum = at;
	for(int q = 1; q <= T; q++)
	{
		if(mp.count(sum)) {printf("%lld\n", q * T - mp[sum] + 1); return 1;}
		sum = sum * at % p;
	}
	return 0;
}
void _work() {
	k = ((a * t - t + b) % p + p) % p * power(((a * x - x + b) % p + p) % p, p - 2) % p;
	if(!(a % p) && !(k % p)) puts("2"); else if(!(k % p)) puts("-1");
	else {BS(); if(!GS()) puts("-1");}
}
void work() {
	p = read(); a = read(); b = read(); x = read(); t = read();
	if(x == t) puts("1");
	else if(a == 1) printf("%lld\n", b ? (t - x % p + p) % p * power(b, p - 2) % p + 1 : -1ll);
	else if(a == 0) if(b == t) puts("2"); else puts("-1");
	else _work();
}
/*----------------------------------------函数*/
signed main() {
	_T = read(); while(_T--) work();
	return 0;
}


积性函数

定义 : 若 \(\gcd(x, y) = 1\)\(f(xy) = f(x)f(y)\)\(f(n)\) 为积性函数

性质

\(f(x)\)\(g(x)\) 均为积性函数 则以下函数也为积性函数:

\(h(x) = f(x^p) \\ h(x) = f^p(x) \\ h(x) = f(x)g(x) \\ h(x) = \sum_{d \mid x}f(d)g(\frac xd)\)

常见的积性函数

  • 单位函数 \(e(n) = [n = 1]\)

  • 幂函数 \(id_k(n) = n^k\) (\(id_1(n)\) 通常记为 \(id(n)\))

  • 常数函数 \(1(n) = 1\)

  • 因数函数 \(d(n) = \sum_{d \mid n} 1\)

  • 除数函数 \(\sigma _k(n) = \sum_{d \mid n}d^k\)

    \(k = 0\) 时 为因数个数函数 \(\sigma_0(n)\)

    \(k = 1\) 时 为因数和函数 \(\sigma(n)\)

  • 欧拉函数 \(\varphi(n) = \sum_{i = 1}^n[\gcd(i, n) = 1]\)

  • 莫比乌斯函数 \(\mu(n) = \begin{cases}1 & n = 1 \\ 0 & n 含有平方因子 \\ (-1)^k & k 为 n 的本质不同质因子个数 \end{cases}\)

比较假

莫比乌斯函数

定义 : \(\mu(n) = \begin{cases}1 & n = 1 \\ 0 & n 含有平方因子 \\ (-1)^k & k 为 n 的本质不同质因子个数 \end{cases}\)

\(n = \prod_{i = 1}^kp_i^{c_i}\) 其中 \(p_i\) 为质因子

  1. \(n = 1\)\(\mu(n) = 1\)

  2. $ n \ne 1$ 时

    \(\exists i \in [1, k], c_i > 1\)\(\mu(n) = 0\)

    即当某质因子出现次数大于 \(1\)\(\mu(n) = 0\)

    \(\forall i \in [1, k], c_i = 1\)\(\mu(n) = (-1)^k\)

    即当每个质因子只出现一次时 \(\mu(n) = (-1)^k\) 此处 \(k\) 为质因子的种类数

性质

\(\sum_{d \mid n}\mu(n) = [n = 1]\)

证明没看懂

结论

\([\gcd(i, j) = 1] \Longleftrightarrow \sum_{d \mid \gcd(i, j)}\mu(d)\)

线筛

因为是积性函数 所以可以线筛

先咕了 学莫比乌斯反演的时候再补(看到再补就大概率不补了)

狄利克雷卷积

太假了 人没了

学不会 弃了

定义

定义两个数论函数 \(f, g\) 的狄利克雷卷积为 \((f * g)(n) = \sum_{d \mid n}f(d)g(\frac nd)\)

性质

满足交换律 结合律 分配律

\(e\) 为狄利克雷卷积的单位元 有 \((f * e)(n) = f(n)\)

\(f, g\) 为积性函数 则 \(f * g\) 为积性函数


一些没学或者是学了没学会的东西

\(a \mod m\) 的阶

原根

\(FFT\)

\(NTT\)

二次剩余

组合数取模

积性函数

莫比乌斯函数

狄利克雷卷积

反演

杜教筛

类欧几里得算法

posted @ 2021-06-27 10:37  Blank_space  阅读(65)  评论(2编辑  收藏  举报
// // // // // // //