数学基础 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\) 为质因子
-
\(n = 1\) 时 \(\mu(n) = 1\)
-
$ 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\)
二次剩余
组合数取模
积性函数
莫比乌斯函数
狄利克雷卷积
反演
杜教筛
类欧几里得算法