zoukankan      html  css  js  c++  java
  • 数学基础 3

    数学基础 3

    前言

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


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

    根本学不会

    指数方程

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

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

    可以在 (O(sqrt m)) 的时间内求解 (a^x equiv b mod m) 要求 (a ot 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 ot m)

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

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

    (d_1 = (a, m))(d_1 mid b) 则原方程无解 否则令方程两边同除 (d_1) 得:(frac a{d_1} imes a^{x - 1} equiv frac b{d_1} mod frac m{d_1})((a, frac m{d_1}) e 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} imes 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
    ", 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
    ", 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
    ", (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
    ", 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 imes 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
    ", 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
    ", 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) = egin{cases}1 & n = 1 \ 0 & n 含有平方因子 \ (-1)^k & k 为 n 的本质不同质因子个数 end{cases})

    比较假

    莫比乌斯函数

    定义 : (mu(n) = egin{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 e 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)

    二次剩余

    组合数取模

    积性函数

    莫比乌斯函数

    狄利克雷卷积

    反演

    杜教筛

    类欧几里得算法

  • 相关阅读:
    C++中几种字符串表示方法
    oracle11g卸载(win10)
    Dbvisualizer 连接oracle数据库
    严重: Exception starting filter struts2 Unable to load configuration.
    eclipse启动Tomcat服务输入http://localhost:8080/报404
    Tomcat内存溢出解决办法
    A Java Runtime Environment(JRE) or Java Development Kit (JDK) must be available in order to run Eclipse.
    Spring容器装配bean的方式
    Spring容器的基本实现
    spring环境搭建
  • 原文地址:https://www.cnblogs.com/blank-space-/p/14940034.html
Copyright © 2011-2022 走看看