dls的数论-同余,欧拉函数,逆元

同余

// 常用知识
a==b(mod m)  <---> m|(a-b)
a==b(mod m) 并且 a==b(mod n) --> m|(a-b) n|(a-b) ---> [n, m]|(a-b) --> a==b(mod [n, m])
(k, m) = d, ka = ka'(mod m)  --> a==a'(mod m/d) 
告诉了我们如何在同余式两边同时除掉一个东西,同时乘上一个数是显然正确的
证明:m|k(a-a')  (m/d)|(k/d)(a-a') 所以有(m/d)和(k/d)互质,所以(m/d)|(a-a') 所以a=a'(mod m/d)
// 线性同余方程
ax==b(mod m) --> ax-my==b --> 扩展欧几里得求
扩展方法(感觉用处不是很大): ax=b(mod m), mx==0(mod m),对前面的x进行辗转相除就可以了,也能求到一个x的
解,主要的问题是后面b的位置的数可能需要开到longlong尽管a,b没有到longlong,而且需要较多的取mod操作,效
率也略低于扩展欧几里得

欧拉函数

// 简化剩余系
所有的n满足0<n<=m,(n, m)=1,构成了一个mod m的简化剩余系,其实就是0-m中和m互质的数和m构成的一个简化剩余系,记这样的个数是f(x)=m*求积(1-1/p), 其中p是m的质因数,公式的证明参考容斥

#include<bits/stdc++.h>

using namespace std;
typedef long long LL;

int main(){
	int T;
	cin >> T;
	while(T--){
		int n;
		scanf("%d", &n);
		int res = n;
		for(int i = 2; i <= n/i; i++){
			if(n % i == 0){
				res = (LL)res * (i - 1) / i;
				while(n % i == 0) n /= i;
			}
		}
		if(n > 1) res = (LL) res * (n - 1) / n;
		printf("%d\n", res);
	}	
	return 0;
}
// 欧拉定理
(a, m) == 1, a^f(m) == 1(mod m), 其中f(m)为m的欧拉函数
特殊的有m是一个指数,f(m)=p-1, 所以有a^(p-1)==1(mod m)

假设与m互质的数是p1,p2....pf(m),有这样一个性质ap1,ap2....apf(m),只是上面一个另一种排列,那么
a^(f(m))p1p2..p(f(m))==p1p2..pf(m)(mod m)
所以有a^(f(m))=1(mod m)

求逆元

(a, m) = 1, ax=1(mod m), x是a的逆元
如果m是素数的话,a^(p-2)=1(mod m) 直接用费马小定理就可以了
如果m不是素数的话,a^(f(m) -1) = 1(mod m)

求1-n的逆元,使用递推减少一个log的常数
inv[i] = (p-p/i) * inv[p mod i] mod p
证明:p == 0 ==(p mod i) + (p/i)*i 一其中p/i是整除
    -(p/i)*i = (p mod i) (mod p)
    -p/i == (p mod i) * i^-1 ( mod p)
    -p/i * (p mod i) ^-1 = i ^ -1 ( mod p)
    
    
#include<bits/stdc++.h>

using namespace std;
typedef long long LL;
const int N = 1e7+10;
int inv[N];
int main(){
	int p, n;
	scanf("%d %d", &p, &n);
	inv[1] = 1;
	int ans = 1;
	for(int i = 2; i <= n; i++){
		inv[i] = (LL)(p - p/i) * inv[p % i] % p;
		ans ^= inv[i];
	}
	printf("%d\n", ans);
	return 0;
}

si=a1...ai
ti=si^-1=a1^-1....ai^-1
利用线性递推求出si和ti,然后ai^-1=si-1*ti

#include<bits/stdc++.h>

using namespace std;
typedef long long LL;
const int N = 1e7+10;
int a[N], s[N], t[N];
unsigned int A, B, C;
int p, n;
inline unsigned int rng61() {
    A ^= A << 16;
    A ^= A >> 5;
    A ^= A << 1;
    unsigned int t = A;
    A = B;
    B = C;
    C ^= t ^ A;
    return C;
}

int exgcd(int a, int b, int &x, int &y){
	if(!b){
		x = 1, y = 0;
		return a;
	}
	int d = exgcd(b, a%b, y, x);
	y -= a/b*x;
	return d;
}
int main() {
    scanf("%d%d%u%u%u", &p, &n, &A, &B, &C);
    int ans = 0;
    for (int i = 1; i <= n; i++){
        a[i] = rng61()%p;
        if(a[i] == 0){
        	a[i] = 1;
        	ans ^= 1;
        }
    }
    s[0] = 1;
    for(int i = 1; i <= n; i++) s[i] = (LL)s[i-1] * a[i] % p;
    // for(int i = 1; i <= n; i++) cout << s[i] << endl;
    int x, y;
	exgcd(s[n], p, x, y);
	if(x < 0) x += p;
	t[n] = x;
	for(int i = n-1; i >= 1; i--) t[i] = (LL)t[i+1] * a[i+1] % p;
	// for(int i = 1; i <= n; i++) cout << t[i] << endl;
	for(int i = 1; i <= n; i++){
		ans ^= (LL)s[i-1] * t[i] % p;
	}
	printf("%d\n", ans);
}
posted @ 2022-03-12 23:41  牛佳文  阅读(149)  评论(0编辑  收藏  举报