• 数论专题


    持续更新

    A - 乘法逆元

    (1∼n) 中的所有数在模 (p) 意义下的乘法逆元

    1.快速幂

    根据欧拉定理,若(a)(p)互质,则(a^{varphi(p)}equiv1;(mod;p)),当(p)是质数,则满足:
    (p) 为质数, (a) 为正整数, (a)(p) 互质, 则(a^{p-1} equiv 1;(mod;p)).
    根据费马小定理: (a imes a^{p-2} equiv 1;(mod ; p)), (a^{p-2};(mod;p))即为(a)的逆元, 利用快速幂求解即可.

    
    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    int n, p;
    
    int pow_mod(int a, int b, int p)
    {
    	int res = 1;
    	while(b)
    	{
    		if(b & 1) res = (LL)res * a % p;
    		a = (LL)a * a % p;
    		b >>= 1;
    	}
    	return res;
    }
    
    int main()
    {
    	scanf("%d%d", &n, &p);
    	for(int i = 1; i <= n; ++ i)
    		printf("%d
    ", pow_mod(i, p - 2, p));
    	return 0;	
    } 
    

    2.扩展欧几里得

    (a)(p)互质,但(p)不是质数时,解线性同余方程(a*xequiv1;(mod;p)):
    转化为:(a*x+p*yequiv1),因为(a)(p)互质,所以一定有解,用exgcd求解即可
    exgcd解出的逆元有可能是负数,转化成(mod;p)意义下的正数即可

    
    #include <bits/stdc++.h>
    using namespace std;
    
    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()
    {
    	int n, p;
    	scanf("%d%d", &n, &p);
    	for(int i = 1; i <= n; ++ i)
    	{
    		int x, y;
    		exgcd(i, p, x, y);
    		x = (x % p + p) % p;
    		printf("%d
    ", x);
    	}
    	return 0;
    } 
    

    3.线性递推

    (p = k * i + r), (k)(dfrac{p}{i})的商,(r)是余数
    (k*i+requiv0;(mod;p)), 两边同时乘上(i^{-1})(r^{-1})
    (k * r^{-1} + i^{-1} equiv 0;(mod;p))
    (i^{-1} equiv -k * r^{-1};(mod;p))
    (i^{-1} equiv -leftlfloordfrac{p}{i} ight floor * (p;mod;i)^{-1};(mod;p))
    且已知(1^{-1}equiv1;(mod;p)),则可以线性递推

    
    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    const int N = 3e6 + 20; 
    int inv[N];
    
    int main()
    {
    	int n, p;
    	scanf("%d%d", &n, &p);
    	inv[1] = 1; puts("1");
    	for(int i = 2; i <= n; ++ i)
    	{
    		inv[i] = (LL)(p - p / i) * inv[p % i] % p;
    		printf("%d
    ", inv[i]);
    	}
    	return 0;
    }
    

    B - 除数函数求和 1

    (sigma_k(n) = sum_{d|n}d^k), 求(sum_{i=1}^nsigma_k(i))的值对(10^9 + 7)取模的结果.

    考虑每个因子(d)对答案的贡献,即(sumlimits_{i = 1}^n i^k * leftlfloordfrac{n}{i} ight floor)
    然后暴力处理(i^k),复杂度(O(nlogk))

    
    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    const int P = 1e9 + 7;
    
    int pow_mod(int a, int b, int p)
    {
    	int res = 1;
    	while(b) 
    	{
    		if(b & 1) res = (LL)res * a % p;
    		a = (LL)a * a % p;
    		b >>= 1;
    	}
    	return res;
    }
    
    int main()
    {
    	int n, k;
    	scanf("%d%d", &n, &k);
    	int res = 0;
    	for(int i = 1; i <= n; ++ i)
    		res = (res + (LL)n / i * pow_mod(i, k, P) % P) % P;
    	printf("%d", res);
    	return 0;
    }
    

    考虑继续优化:在求幂时有重复计算,因为每个数都可以唯一分解,所以只需要计算质因子的幂即可
    考虑线性筛,用每个数的质因子的幂去计算它的幂.

    
    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    const int P = 1e9 + 7;
    const int N = 1e7 + 10;
    
    bool st[N];
    int primes[N], cnt;
    int mi[N];
    
    int pow_mod(int a, int b, int p)
    {
    	int res = 1;
    	while(b) 
    	{
    		if(b & 1) res = (LL)res * a % p;
    		a = (LL)a * a % p;
    		b >>= 1;
    	}
    	return res;
    }
    
    void init(int n, int k)
    {
    	mi[1] = 1;
    	for(int i = 2; i <= n; ++ i)
    	{
    		if(!st[i]) 
    		{
    			primes[cnt ++ ] = i;
    			mi[i] = pow_mod(i, k, P); 
    		}
    		for(int j = 0; primes[j] * i <= n; ++ j)
    		{
    			st[primes[j] * i] = 1;
    			mi[primes[j] * i] = (LL)mi[i] * mi[primes[j]] % P;
    			if(i % primes[j] == 0) break;
    		}
    	}
    }
    
    int main()
    {
    	int n, k;
    	scanf("%d%d", &n, &k);
    	init(n, k);
    	int res = 0;
    	for(int i = 1; i <= n; ++ i)
    		res = (res + (LL)n / i * mi[i] % P) % P;
    	printf("%d
    ", res);
    	return 0;
    }
    

    C - 除数函数求和 2

    (sigma_k(i) = sum_{d|i}d^k)
    (sum_{i=1}^n2sigma_2(i)+3sigma_1(i)+5sigma_0(i))(998244353)取模.

    和上题一样考虑每个因子的贡献,转化为求(sumlimits_{i=1}^n(2i^2+3i+5) * leftlfloordfrac{n}{i} ight floor)
    (n)的范围在(10^9)内,考虑整除分块
    转化为(2sumlimits_{i=1}^ni^2leftlfloordfrac{n}{i} ight floor + 3sumlimits_{i=1}^nileftlfloordfrac{n}{i} ight floor + 5sumlimits_{i=1}^nleftlfloordfrac{n}{i} ight floor)
    且已知:
    (sumlimits_{i=1}^n1=n)
    (sumlimits_{i=1}^ni=dfrac{(1+n)*n}{2})
    (sumlimits_{i=1}^ni^2=dfrac{n*(n+1)*(2n+1)}{6})
    注:运算都是在(mod;p)意义下的,故除法要乘逆元;且做减法后可能会出现负数,转化为(mod;p)意义下的正数

    
    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    
    const int P = 998244353;
    const int inv3 = 332748118;
    const int inv2 = 499122177;
     
    int g(int k, int x)
    {
    	return k / (k / x);	
    }
    
    int f2(int l, int r)
    {
    	int res1 = 1, res2 = 1;
    	l --;
    	res1 = (LL)res1 * l % P;
    	res1 = (LL)res1 * (l + 1) % P;
    	res1 = (LL)res1 * (2 * l + 1) % P;
    	res2 = (LL)res2 * r % P;
    	res2 = (LL)res2 * (r + 1) % P;
    	res2 = (LL)res2 * (2 * r + 1) % P;
    	int res = res2 - res1;
    	res = (res % P + P) % P;
    	res = (LL)res * inv3 % P;
    	return res; 
    } 
    
    int f1(int l, int r)
    {
    	int res = 1;
    	res = (LL)res * (l + r) % P;
    	res = (LL)res * (r - l + 1) % P;
    	res = (LL)res * 3 % P;
    	res = (LL)res * inv2 % P;
    	return res; 
    }
    
    int f0(int l, int r)
    {
    	int res = 1;
    	res = (LL)res * (r - l + 1) % P;
    	res = (LL)res * 5 % P;
    	return res; 
    } 
    
    int main()
    {
    	int n;
    	scanf("%d", &n);
    	int res = 0;
    	for(int l = 1, r; l <= n; l = r + 1)
    	{
    		r = min(n, g(n, l));
    		res = (res + (LL)f0(l, r) * (n / l) % P) % P;
    		res = (res + (LL)f1(l, r) * (n / l) % P) % P;
    		res = (res + (LL)f2(l, r) * (n / l) % P) % P;
    	}
    	printf("%d
    ", res);
    	return 0;
    } 
    

    D - 质数判定

    判定输入的数是不是质数。

    Miller_Rabin判质数,要用__int128或者快速乘

    
    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef long double LD;
    
    /*
    LL mul(LL a, LL b, LL p)
    {
        __int128 x = a, y = b, m = p;
        return (LL)(x * y % m);
    }
    */
    
    LL mul(ULL a, ULL b, LL p) 
    {
        return (a * b - (ULL)((LD)a / p * b) * p + p) % p;
    }
    
    /*
    LL mul(LL a, LL b, LL p)
    {
    	LL res = 0;
    	while(b)
    	{
    		if(b & 1) res = (res + a) % p;
    		a = a * 2 % p;
    		b >>= 1;
    	}
    	return res;
    }
    */
    
    LL power(LL a, LL b, LL p)
    {
    	LL res = 1;
    	while(b)
    	{
    		if(b & 1) res = mul(res, a, p);
    		a = mul(a, a, p);
    		b >>= 1;
    	}
    	return res;
    }
    
    LL p[20] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};
    
    bool Miller_Rabin(LL n)
    {
    	if(n == 1) return 0;
    	for(int i = 1; i <= 9; ++ i)
    	{
    		if(p[i] == n) return 1;
    		else if(p[i] > n) return 0;
    		LL sum = power(p[i], n - 1, n), x = n - 1;
    		if(sum != 1) return 0;
    		while(sum == 1 && !(x % 2))
    		{
    			x >>= 1; 
    			sum = power(p[i], x, n);
    			if(sum != 1 && sum != n - 1) return 0;
    		}
    	}
    	return 1;
    }
    
    int main()
    {
    	LL n; 
    	while(scanf("%lld", &n) == 1)
    	{	
    		puts(Miller_Rabin(n) ? "Y" : "N");
    	}
    	return 0;
    }
    

    E - 乘法逆元 2

    (sum_{i=1}^na_i^{-1} imes998244353^{n-i};(mod;p))
    (1 le n le 5000000,;1le a_i < p,; p=10^9 + 7)

    解决此题之前先考虑如何(O(n))求阶乘的逆元
    考虑如下递推式:
    (infact[n])(n!)的逆元
    (infact[i + 1] = dfrac{1}{(i + 1)!})
    (infact[i + 1] * (i + 1) = dfrac{1}{i!} = infact[i])
    故我们可以求出(n!)的逆元,然后逆推,得到(1...n!)所有的逆元
    同理,还可以用(infact[i] * (i - 1)! = i^{-1})(O(n))得到所有(i)的逆元

    
    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    const int N = 3e6 + 20;
    
    int fact[N], infact[N];
    
    int pow_mod(int a, int b, int p)
    {
    	int res = 1;
    	while(b)
    	{
    		if(b & 1) res = (LL)res * a % p;
    		a = (LL)a * a % p;
    		b >>= 1;
    	}
    	return res;
    }
    
    int main()
    {
    	int n, p;
    	scanf("%d%d", &n, &p);
    	fact[0] = 1;
    	for(int i = 1; i <= n; ++ i) fact[i] = (LL)fact[i - 1] * i % p;
    	
    	infact[n] = pow_mod(fact[n], p - 2, p);
    	
    	for(int i = n - 1; i >= 1; -- i)
    		infact[i] = (LL)infact[i + 1] * (i + 1) % p;
    	
    	for(int i = 1; i <= n; ++ i)
    	{
    		int res = (LL)infact[i] * fact[i - 1] % p;
    		printf("%d
    ", res);
    	}
    	return 0;
    } 
    

    本题可以考虑相同的思路
    做前缀积 (fact[n] = prodlimits_{i=1}^na_i)
    求出(infact[n]),用(infact[i + 1] * a_{i + 1} = infact[i])递推所有前缀积的逆元
    然后用(infact[i] * fact[i - 1] = a_i^{-1})(O(n))得到所有(a_i)的逆元

    
    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    const int P = 1e9 + 7;
    const int M = 998244353;
    const int N = 5e6 + 20;
    
    int a[N];
    int fact[N], infact[N];
    
    int pow_mod(int a, int b, int p)
    {
    	int res = 1;
    	while(b)
    	{
    		if(b & 1) res = (LL)res * a % p;
    		a = (LL)a * a % p;
    		b >>= 1;
    	}
    	return res;
    }
    
    int main()
    {
    	int n;
    	scanf("%d", &n);
    	for(int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
    
    	fact[0] = 1;
    	for(int i = 1; i <= n; ++ i) fact[i] = (LL)fact[i - 1] * a[i] % P;
    	
    	infact[n] = pow_mod(fact[n], P - 2, P);
    	
    	for(int i = n - 1; i >= 1; -- i)
    		infact[i] = (LL)infact[i + 1] * a[i + 1] % P;
    	
    	int ans = 0;
    	for(int i = 1; i <= n; ++ i)
    	{
    		int res = (LL)infact[i] * fact[i - 1] % P;
    		ans = (LL)ans * M % P;
    		ans = ((LL)ans + res) % P;
    	}
    	printf("%d
    ", ans);
    	return 0;
    } 
    

    F - 快速幂 2

    (x^{a_i};(mod;p))
    (1 le n le 5 imes 10^6,;1le x,a_i < p,; p = 998244352)

    直接暴力快速幂的复杂度(O(nlogp))
    考虑分块预处理
    (y = leftlfloordfrac{y}{k} ight floor cdot k + y ;mod; k)
    (x^y = x^{y;mod;k} cdot x^{leftlfloordfrac{y}{k} ight floor cdot k})
    预处理复杂度(O(k + dfrac{p}{k})), 当(k)(sqrt p + 1)时最优
    预处理后即可(O(1))回答每个询问

    
    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    const int N = 5e6 + 20;
    const int P = 998244352;
    
    int a[N], x_i[N], x_ki[N];
    int x, n;
    
    int main()
    {
    	scanf("%d%d", &x, &n);
    	int k = sqrt(P) + 1;
    	x_i[0] = 1;
    	for(int i = 1; i <= k; ++ i) x_i[i] = (LL)x_i[i - 1] * x % P;
    	x_ki[0] = 1;
    	for(int i = 1; i <= P / k; ++ i) x_ki[i] = (LL)x_ki[i - 1] * x_i[k] % P;
    	for(int i = 1; i <= n; ++ i)
    	{
    		int y;
    		scanf("%d", &y);
    		int res = (LL)x_i[y % k] * x_ki[y / k] % P; 	
    		printf("%d ", res);
    	}
    	puts("");
    	return 0;
    } 
    

    G - 二项卷积

    H - 模立方根

    I - ZQC 的作业

    J - Humble Numbers

    求第(n)个质因子只有(2,3,5,7)的数

    
    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 6000;
    
    int f[N];
    
    void init()
    {
    	f[1] = 1;
    	int a = 1, b = 1, c = 1, d = 1;
    	for(int i = 2; i <= 5842; ++ i)
    	{
    		f[i] = min(min(f[a] * 2, f[b] * 3), min(f[c] * 5, f[d] * 7));
    		if(f[i] == f[a] * 2) a ++;
    		if(f[i] == f[b] * 3) b ++;
    		if(f[i] == f[c] * 5) c ++;
    		if(f[i] == f[d] * 7) d ++;
    	}	
    }
    
    int main()
    {
    	init();
    	int n;
    	while(scanf("%d", &n) == 1 && n)
    	{
    		if(n % 10 == 1 && n % 100 != 11) printf("The %dst humble number is %d.
    ", n, f[n]);
    		else if(n % 10 == 2 && n % 100 != 12) printf("The %dnd humble number is %d.
    ", n, f[n]);
    		else if(n % 10 == 3 && n % 100 != 13) printf("The %drd humble number is %d.
    ", n, f[n]);
    		else printf("The %dth humble number is %d.
    ", n, f[n]);
    	} 
    	return 0;
    } 
    

    K - X问题

    求在小于等于(N)的正整数中有多少个(X)满足:
    (X;mod;a_0=b_0,;X;mod;a_1=b_1,;X;mod;a_2=b_2,;…,;X;mod;a_i=b_i,;…;(0 < a_i le 10))

    扩展中国剩余定理, 去掉了模数两两互质的条件
    先从两个方程入手
    (egin{cases}x = k_1a_1 + m_1\x = k_2a_2 + m_2end{cases})
    (k_1a_1 + m_1 = k_2a_2 + m_2)
    (k_1a_1 - k_2a_2 = m_2 - m_1)
    ((a_1,a_2);|;(m_2 - m_1)),则有解
    通解(egin{cases}k_1 + kdfrac{a_2}{d}\k_2 + kdfrac{a_1}{d}end{cases})
    (x = k_1a_1 + m_1 = (k_1 + kdfrac{a_2}{d})a_1 + m_1)
    (x = a_1k_1 + m_1 + k[a_1, a_2])
    (a_1k_1 + m_1 = m), ([a_1, a_2] = a)
    (x = m + ka)
    则将两个不定方程合并成了一个,合并(n - 1)次后只剩一个方程
    即为 (x equiv m;(mod;a))
    最小正整数解即为(m;mod;a)的正余数,然后即可求出小于等于(N)的正整数中(x)的个数.

    
    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    const int N = 10 + 2;
    
    LL exgcd(LL a, LL b, LL &x, LL &y)
    {
    	if(!b)
    	{
    		x = 1, y = 0;
    		return a;
    	}	
    	LL d = exgcd(b, a % b, y, x);
    	y -= a / b * x;
    	return d;
    }
    
    LL a[N], b[N];
    
    int main()
    {
    	int __;
    	scanf("%d", &__);
    	while(__ -- )
    	{
    		LL n, m;
    		scanf("%lld%lld", &m, &n);
    		for(int i = 1; i <= n; ++ i) scanf("%lld", &a[i]);
    		for(int i = 1; i <= n; ++ i) scanf("%lld", &b[i]);
    		
    		LL a1 = a[1], m1 = b[1];
    	
    		bool flag = 0;
    		for(int i = 2; i <= n; ++ i)
    		{
    			LL a2 = a[i], m2 = b[i];
    			LL k1, k2;
    			LL d = exgcd(a1, a2, k1, k2);
    			if((m2 - m1) % d) { flag = 1; break; }
    			k1 *= (m2 - m1) / d;
    			LL t = a2 / d;
    			k1 = (k1 % t + t) % t;
    			m1 = a1 * k1 + m1;
    			a1 = abs(a1 / d * a2); 
    		}
    		if(flag) puts("0");
    		else 
    		{
    			LL res = (m1 % a1 + a1) % a1;
    			if(res > m) puts("0");
    			else if(res == 0) printf("%lld
    ", (m - res) / a1);
    			else printf("%lld
    ", (m - res) / a1 + 1);
    		}
    	}
    	return 0;
    }
    

    L - GCD

    求满足(a le x le b,;c le y le d,;gcd(x, y) = k)((x,y))数量.
    且(5,7)和(7,5)被认为是相同的.

    
    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    
    const int N = 1e5 + 20;
    
    int primes[N], cnt, mu[N], sum[N];
    bool st[N]; 
    
    void init()
    {
    	mu[1] = 1;
    	for(int i = 2; i < N; ++ i)
    	{
    		if(!st[i]) 
    		{
    			primes[cnt ++ ] = i;
    			mu[i] = -1;
    		}
    		for(int j = 0; primes[j] * i < N; ++ j)
    		{
    			st[primes[j] * i] = 1;
    			if(i % primes[j] == 0) break;
    			mu[primes[j] * i] = -mu[i];
    		}
    	}
    	for(int i = 1; i < N; ++ i) sum[i] = sum[i - 1] + mu[i]; 
    }
    
    int g(int k, int x)
    {
    	return k / (k / x);	
    }
    
    LL f(int a, int b, int k)
    {
    	LL res1 = 0, res2 = 0;
    	a = a / k, b = b / k;
    	int n = min(a, b);
    	for(int l = 1, r; l <= n; l = r + 1)
    	{
    		r = min(n, min(g(a, l), g(b, l)));
    		res1 += (LL)(sum[r] - sum[l - 1]) * (a / l) * (b / l);
    	}	
    	for(int l = 1, r; l <= n; l = r + 1)
    	{
    		r = min(n, g(n, l));
    		res2 += (LL)(sum[r] - sum[l - 1]) * (n / l) * (n / l);
    	}
    	return res1 - res2 / 2;	
    }
    
    int main()
    {
    	init();
    	int __, cnt = 0;
    	scanf("%d", &__);
    	while(__ -- )
    	{
    		int a, b, c, d, k;
    		scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);
    		if(k == 0) { printf("Case %d: 0
    ", ++ cnt); continue; }
    		LL res = f(b, d, k) - f(a - 1, d, k) - f(b, c - 1, k) + f(a - 1, c - 1, k);
    		printf("Case %d: %lld
    ", ++ cnt,res);
    	}
    	return 0;
    }
    

    M - GCD Again

    
    #include <bits/stdc++.h>
    using namespace std;
    
    int main()
    {
    	int n;
    	while(scanf("%d", &n) == 1 && n)
    	{
    		int res = n, m = n;
    		for(int i = 2; i <= n / i; ++ i)
    		{
    			if(n % i == 0)
    			{
    				while(n % i == 0) n /= i;
    				res = res / i * (i - 1);
    			}
    		}
    		if(n > 1) res = res / n * (n - 1);
    		printf("%d
    ",m - res - 1);
    	}
    	return 0; 
    } 
    

    N - The Euler function

    (sumlimits_{i=a}^bφ(i))

    欧拉函数是积性函数,用线性筛预处理即可

    
    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    const int N = 3e6 + 20;
    
    int primes[N], cnt;
    int phi[N];
    bool st[N];
    
    void get_euler(int n)
    {
    	phi[1] = 1;
    	for(int i = 2; i <= n; ++ i)
    	{
    		if(!st[i]) 
    		{
    			phi[i] = i - 1;
    			primes[cnt ++] = i;
    		}
    		for(int j = 0; primes[j] <= n / i; ++ j)
    		{
    			st[primes[j] * i] = 1;
    			if(i % primes[j] == 0)
    			{
    				phi[i * primes[j]] = phi[i] * primes[j];
    				break;
    			}
    			phi[primes[j] * i] = phi[i] * (primes[j] - 1);
    		}
    	}
    }
    
    int main()
    {
    	get_euler(N - 1);
    	int a, b;
    	while(scanf("%d%d", &a, &b) == 2)
    	{
    		LL res = 0;
    		for(int i = a; i <= b; ++ i)
    			res += phi[i];
    		printf("%lld
    ", res);
    	}
    	return 0;
    }
    

    O - Fansblog

    P - Discrete Logging

    
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath> 
    using namespace std;
    
    const int N = 2e5 + 3;
    const int null = 0x3f3f3f3f; 
    typedef long long LL; 
    
    int Hash[N], h[N];
    
    int find(int x)
    {
    	int k = (x % N + N) % N;
    	
    	while(Hash[k] != null && Hash[k] != x)
    	{
    		k ++;
    		if(k == N) k = 0;
    	}
    	
    	return k;
    } 
    
    bool count(int x)
    {
    	int k = (x % N + N) % N;
    	while(1)
    	{
    		if(Hash[k] == null) return 0;
    		if(Hash[k] == x) return 1;
    		k ++;
    		if(k == N) k = 0;
    	}
    	return 0;
    }
    
    int bsgs(int a, int b, int p)
    {
    	memset(Hash, 0x3f, sizeof Hash);
    	if(1 % p == b % p) return 0;
    	int k = sqrt(p) + 1;
    	for(int i = 0, j = b % p; i < k; ++ i) 
    	{
    		int k = find(j);
    		Hash[k] = j;
    		h[k] = i;
    		j = (LL)j * a % p;
    	}
    	int ak = 1;
    	for(int i = 0; i < k; ++ i) ak = (LL)ak * a % p;
    	for(int i = 1, j = ak % p; i <= k; ++ i)
    	{
    		if(count(j)) return (LL)i * k - h[find(j)];
    		j = (LL)j * ak % p;
    	}
    	return -1;
    }
    
    int main()
    {
    	int a, p, b;
    	while(scanf("%d%d%d", &p, &a, &b) == 3)
    	{
    		if(a == 0 && p == 0 && b == 0) break;
    		int res = bsgs(a, b, p);
    		if(res == -1) puts("no solution");
    		else printf("%d
    ", res);
    	}
    	return 0;
    }
    

    Q - The Embarrassed Cryptographer

    R - Minimum Sum LCM

    S - GCD - Extreme (I)

    T - Colossal Fibonacci Numbers!

    U - One Friend at a Time

    V - X^A Mod P

    W - 乘法逆元

    (M)(N)互质,求满足K * M % N = 1的最小正整数K.

    同A题,扩展欧几里得求逆元

    
    #include <bits/stdc++.h>
    using namespace std;
    
    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()
    {
    	int n, m;
    	scanf("%d%d", &m, &n);
    	int x, y;
    	int d = exgcd(m, n, x, y);
    	printf("%d
    ", (x % n + n) % n);
    	return 0;
    }
    

    X - 中国剩余定理

    一个正整数(K),给出(K;Mod;)一些质数的结果,求符合条件的最小的(K)

    中国剩余定理
    (egin{cases}x equiv a_1;(mod;m_1)\x equiv a_2;(mod;m_2)\...\x equiv a_k;(mod;m_k)end{cases})
    (M = m_1m_2...m_k)
    (M_i = dfrac{M}{m_i})
    (M_i^{-1})表示(M_i)(mod;m_i)条件下的逆元
    (x = a_1M_1M_1^{-1} + a_2M_2M_2^{-1} + ... + a_kM_kM_k^{-1})

    
    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    const int N = 10 + 2;
    int n;
    int A[N], B[N];
    
    void exgcd(LL a, LL b, LL &x, LL &y)
    {
    	if(!b)
    	{
    		x = 1, y = 0;
    		return;
    	}
    	exgcd(b, a % b, y, x);
    	y -= a / b * x;
    }
    
    int main()
    {
    	scanf("%d", &n);
    	LL M = 1;
    	for(int i = 0; i < n; ++ i)
    	{
    		scanf("%d%d", &A[i], &B[i]);
    		M *= A[i];
    	}
    	
    	LL res = 0;
    	for(int i = 0; i < n; ++ i)
    	{
    		LL Mi = M / A[i];
    		LL ti, y;
    		exgcd(Mi, A[i], ti, y);
    		res += B[i] * Mi * ti;
    	}
    	printf("%lld
    ", (res % M + M) % M);
    	return 0;
    } 
    
  • 相关阅读:
    Icinga使用总结
    Linux入门:usermod
    JMeter入门(01)概念和样例
    英语日常词汇:living-room、dining-room vs dining hall
    安装 docker-compose
    CentOS7下安装python-pip
    JMeter入门(03)多台JMeter联合测试
    jmeter入门(02)测试报告各项指标含义
    istio入门(01)istio的优势在哪里?
    Docker学习笔记
  • 原文地址:https://www.cnblogs.com/ooctober/p/14312516.html
Copyright © 2020-2023  润新知