归并排序和逆序对问题
归并排序 归 …
May all the beauty be blessed.
形如a≡b (mod d)的式子被称为同余公式,因为此式中a与b模d后的值相等,故被称为同余公式。相关性质将基于它展开。
它等价于(a-b)|d、a-(a/d)*d=b、a=b+nd (n∈Z)。
(a + b) mod p = (a mod p + b mod p) mod p
(a – b) mod p = (a mod p – b mod p) mod p
(a * b) mod p = (a mod p * b mod p) mod p
ab mod p = ((a mod p)b) mod p
结合率: ((a + b) mod p + c) mod p = (a + (b + c) mod p) mod p
((a * b) mod p * c) mod p = (a * (b * c) mod p) mod p
交换率: (a + b) mod p = (b+a) mod p
(a * b) mod p = (b * a) mod p
分配率: ((a + b) mod p * c) mod p = ((a * c) mod p + (b * c) mod p) mod p
重要定理:若a≡b (mod p),则对于任意的c,都有(a + c) ≡ (b + c) (mod p)
若a≡b (mod p),则对于任意的c,都有(a * c) ≡ (b * c) (mod p)
若a≡b (mod p),则对于任意的c,都有ac≡ bc (mod p)
快速幂是运用分治思想降低朴素算法复杂度的算法,是OI中大数据常用的优化小trick。
假设我们现在正在解决求a^b的问题,其中b非常大,而且通常会遇到朴素算法运算中,中间得数就已经会爆int甚至爆long long的情况。
我们知道a^b=(a^(b/2))^2,因此我们可以将求a^b问题转化为求a^(b/2)问题,如此递归下去,总会遇到b/2=0的时候,此时递归就到头了。这样做的时间复杂度是O(logn)的(而朴素是O(n)的)。
我们还可以运用取模运算的性质(a * b) mod p = (a mod p * b mod p) mod p来对每一步的值取模缩小值的范围。此算法便是边幂边取模的算法。
如果b是一个单数怎么办?也不要紧:a^b=(a^(b/2))^2*a即可解决。
下面是递归式快速幂。
int fpow(int x, int p) { // 求x^p
if(p == 0) return 1;
int t = fpow(x, p / 2);
if(p % 2 == 0) {
return t * t;
} else {
return t * t * x;
}
}
int fpow_m(int x, int p, int m) { // 求(x^p)%m
if(p == 0) return 1;
int t = fpow_m(x, p / 2, m) % m;
if(p % 2 == 0) {
return (t * t) % m;
} else {
return ((t * t) % m * (x % m)) % m;
}
}
下面是非递归式快速幂。
inline LL fpow(LL x, LL k) {
LL t = 1;
while(k) {
if(k & 1) t = (t * x) % MO;
x = (x * x) % MO;
k >>= 1;
}
return t;
}
应用不用说了,常用于数据大的NOIP提高组复赛T1之类的题目。
模运算与同余公式的性质 – 根号下的麻辣烫 – CSDN博客
每行都有一个正整数n,n的位数<=200
3 5 28 792
1051 81 5521
快速幂是肯定得用的,但是同时也考验了高精度幂运算的知识。
此处我用了一个小trick,打表知取2011的k次幂时,只要整数k后三位相等,他们运算后所得数后四位相等。故省去了写高精度的功夫。
#include <cstdio>
#include <cstring>
#include <cstdlib>
int fpow_m(int x, int p, int m) { // 求(x^p)%m
if(p == 0) return 1;
int t = fpow_m(x, p / 2, m) % m;
if(p % 2 == 0) {
return (t * t) % m;
} else {
return ((t * t) % m * (x % m)) % m;
}
}
int n, t;
char s[205];
char tmp[5];
int main() {
scanf("%d", &n);
for(int i = 0; i < n; i++) {
memset(s, 0, sizeof s);
memset(tmp, 0, sizeof tmp);
scanf("%s", s);
int len = strlen(s), cnt = 0;
for(int i = 0; i < 3; i++) {
if(len - 3 + i < 0) continue;
tmp[cnt] = s[len - 3 + i];
cnt++;
}
//printf("p: %s\n", tmp);
printf("%d\n", fpow_m(2011, atoi(tmp), 10000));
}
return 0;
}
快速幂+快速幂经典例题 - - CSDN博客
Copyright © 2017-2022 KSkun's Blog.
Authored by KSkun and his friends.
本博客内所有原创内容采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。引用内容如果侵权,请在此留言。
All original content in this blog is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
If any reference content infringes your rights, please contact us.