标签:数列 最大 result 公倍数 去掉 UI mat img 四十
一些数论基本定理
( a + b ) mod c = ((a mod c) + (b mod c)) mod c
( a * b ) mod c = ((a mod c) * (b mod c)) mod c
消去律:若 gcd(c,p) = 1,则 ac ≡ bc mod p => a ≡ b mod p
消去律证明: ac ≡ bc mod p => ac = bc + kp => c(a-b) = kp
c和p没有除1以外的公因子 => 1) c能整除k 或 2) a = b 如果2不成立,则c|kp c和p没有公因子 => c|k,
所以k = ck‘ => c(a-b)=kp可以表示为c(a-b) =ck‘p 因此a-b = k‘p,得出a ≡ b mod p
快速幂
int Pow (int a,int b) { //快速求a^b ,复杂度 log(b) if(b == 0) return 1; if(b & 1) //b是奇数 { return a * Pow(a,b-1); } else { int t = Pow (a,b/2); return t * t; } }
int Pow(int a,int b) { //快速求a^b ,复杂度 log(b) int result = 1; int base = a; while(b) { if( b & 1) result *= base; base *= base; b >>= 1; } return result; }
快速幂取模
int PowMod(int a,int b,int c) { //快速求 a^b % c ,要避免计算中间结果溢出 int result = 1; int base = a%c; while(b) { if( b & 1) result = (result * base)%c; base = (base * base) % c; b >>= 1; } return result; }
等比数列二分求和取模
Sn= a+a2+...+an 要求 Sn mod p 如果用公式算,可能溢出,因此用二分法求
若 n是偶数
Sn= a+...+an/2 + an/2+1 + an/2+2 +...+ an/2+n/2 =(a+...+an/2) + an/2(a+...+an/2)
=Sn/2+ an/2Sn/2 =(1+an/2)Sn/2
若n是奇数
Sn= a+...+a(n-1)/2 + a(n-1)/2+1 +... + a(n-1)/2+(n-1)/2 + a(n-1)/2+(n-1)/2 + 1
=S(n-1)/2 + a(n-1)/2(a+...+a(n-1)/2)+an =(1+a(n-1)/2)S(n-1)/2+an
int PowSumMod(int a,int n,int p) { // return (a+ a^2 + ... + a^n) Mod p; if( n == 1) return a%p; if( n %2 == 0) return (1+PowMod(a,n/2,p))*PowSumMod(a,n/2,p) % p; else return ((1+PowMod(a,(n-1)/2,p)) * PowSumMod(a,(n-1)/2,p)+ PowMod(a,n,p)) % p; }
POJ3233 Matrix Power Series
矩阵快速幂+等比数列二分求和取模
给一个 n × n 的整数矩阵 A 和正整数k,m,
令 S = A + A 2 + A 3 + … + A k 求 S mod m
(S的每个都 mod m) n (n ≤ 30), k (k ≤ 109 ) and m (m < 104 )
struct Matrix { T a[32][32]; int r; //行列数 Mat(int rr):r(rr) { } void MakeI() //变为单位矩阵 { memset(a,0,sizeof(a)); for(int i = 0; i < r; ++i) a[i][i] = 1; } }; Matrix Pow(const Matrix & m,int k,int p) { //求mk mod p int r = m.r; Matrix result(r); result.MakeI(); //MakeI是将result变为单位矩阵 Matrix base = m; while(k) { if( k & 1) result = Product(result,base,p); //result*base mod p k >>= 1; base = Product(base,base,p); } return result; }
欧几里得算法求最大公约数
int Gcd(int a,int b) { if( b == 0) return a; return Gcd(b,a%b); }
最小公倍数:lcm(a,b) = a*b/gcd(a,b)
扩展欧几里得算法
ax+by=gcd(a,b)
有整数解(x,y) <=> bx+(a%b)y = gcd(a,b)
有整数解(x1,y1),且 x = y1, y = x1-[a/b]*y1
因此,可以在求gcd(a,b)的同时,对 ax+by=gcd(a,b)求解
int GcdEx (int a,int b,int &x ,int & y) //求 ax+by=gcd(a,b)的整数解,返回gcd(a,b) { if( b == 0) { x = 1; y = 0; return a; } int x1,y1; int gcd = GcdEx(b,a%b,x1,y1); x = y1; y = x1- a/b * y1; return gcd; }
ax+by=c 有解的充要条件是
gcd(a,b)|c • 设 d = gcd(a,b), k = c/d, ax+by = d的解是 (x1,y1)
则 ax+by = c的解集是: x = k*x1 + t*(b/d) y = k*y1 – t*(a/d) t为任意整数
扩展欧几里得算法求ax ≡ c(mod b)
求ax ≡ c(mod b)等价于求 ax+by = c
设 d = gcd(a,b), k = c/d, ax+by = d的解是 (x1,y1)
则ax≡c(mod b) 的解集是: x = k*x1 + t*(b/d) t为任意整数 其中模b不同的解共有 d 个,为: x = k*x1 + t*(b/d) t=0,1,..d-1
求ax ≡ c(mod b) 的最小非负整数解: 令 ans = k * x1; s = b/d; 则 x = ans + t*s t为任意整数
则最小非负整数解是:(ans%s + s)%s
中国剩余定理
孙子定理,韩信点兵,隔墙算,鬼谷算,大衍求一术...
"物不知数"问题:"今有物不知其数,三三数之剩二,五 五数之剩三,七七数之剩二,问物几何?答曰:‘二十三.‘ 术曰:三三数之剩二,置一百四十,五五数之剩三,置六 十三,七七数之剩二,置三十,并之,得二百三十三,以二 百一十减之,即得.凡三三数之剩一,则置七十,五五数 之剩一,则置二十一,七七数之剩一,则置十五,即得." --孙子算经
设n组数(ai, bi), 其中bi两两互素
求x使得 x = a1 mod b1 x = a2 mod b2 ... x = an mod bn
给定两两互质的正整数n1,n2,...,nk,要求找到最小的正整 数x,满足方程组x≡ai(mod ni) (i=1,2...k)
算法步骤: 令n=n1n2...nk, mi=n/ni
显然gcd(mi,ni)=1,
利用扩展欧几里德算法计算出xi满 足mixi≡1(mod ni)
x = (a1x1m1+a2x2m2+...+akxkmk) mod n
此方程组任意两个解模 n 同余,因此x就是最小的
此方程组任意两个解模 n 同余 证:设有两个解 x1,x0 则: x1 ≡ ai (mod ni) (i=1,2...k) x0 ≡ ai (mod ni) (i=1,2...k) => ni|(x1-x0) (i=1,2...k) ni|(x1-x0) 且ni两两互质 => n|(x1-x0) => x1 ≡ x0 (mod n)
中国剩余定理的一般情况
给定正整数n1,n2,...,nk(未必两两互质),要求找到x,
满 足x≡ai(mod ni) (i=1,2...k)
x ≡ a1( mod n1)
x ≡ a2( mod n2)
=> x + u*n1 = a1 且 x - v*n2 = a2
=> n1*u + n2*v = (a1-a2) 此关于u,v的方程,当且仅当 gcd(n1,n2)|(a1-a2)时有解
设用扩展欧几里得算法求得 n1*u + n2*v = (a1-a2) 根为 (u0,v0)则:
则此方程解集为: u = u0 + t*(n2/gcd(n1,n2)) v = v0 – t*(n1/gcd(n1,n2)) t为任意整数
x + u*n1 = a1 => x的解集为:a1 – u0n1 – tn1n2/gcd(n1,n2) 即:x = a1 – u0n1 – t*lcm(n1,n2) t为任意整数
x = a1 – u0n1 – t*lcm(n1,n2) t为任意整数
等价于将
x ≡ a1( mod n1)
x ≡ a2( mod n2)
合并为: x ≡ a1 – u0n1 (mod lcm(n1,n2)) 再继续两个方程并为一个,最后就能求得x的解空间
线性筛法求素数
朴素筛法求n以内的所有质数
初始时容器内为2到n的所有数
取出最小的数p,p一定是质数,删去除p外的所有p的倍数
重复上述步骤直到向后找不到没被删掉的数
缺陷:一个数可能被重复删去多次,影响效率
改进: 对每个素数p 考虑所有i,
若i的最小素因子>=p,
则将 i*p去掉 i = q1 *q2 *...qn qi是素数,
q1 >= p i*p = p*q1 *q2 *...qn i*p只会被删掉一次,只在考察p的时候被删,不会在考察q1 q2 qn 的时候被删
int main() { int n; cin >> n; //求n以内素数 vector<int> prime; vector<bool> isPrime(n+1); for(int i = 1; i <= n; ++i) isPrime[i] = true; for(int i = 2; i <= n; ++i) { if( isPrime[i]) //处理到i时它还没被删掉,则i为素数 prime.push_back(i); for(int j = 0; j < prime.size() ; ++j) { if( i*prime[j] <= n) isPrime[i*prime[j]] = false; else break; if( i % prime[j] == 0)// prime[j]是i的最小素因子 break; } } for(int i = 0; i < prime.size(); ++i) cout << prime[i] << endl; return 0; }
标签:数列 最大 result 公倍数 去掉 UI mat img 四十
原文地址:http://www.cnblogs.com/oi-forever/p/8016670.html