输入,计算。
一个暴力的做法就是直接把个乘起来,时间复杂度为
考虑一个递归的计算方法:
ParseError: KaTeX parse error: Undefined control sequence: \mbox at position 27: …gin{cases}
1,&{\̲m̲b̲o̲x̲{如果}}n=0\\
x\,(…
每次递归都会变为原先的一半,所以时间复杂度为。
对于非递归的做法,考虑的二进制表示。
对于每一项是前面一项的平方,
可以在的时间内计算,然后再根据的值,
决定每个是否乘入答案中。
x^1 = x
x^2 = x^1 * x^1 % p
x^4 = x^2 * x^2 % p
x^8 = x^4 * x^4 % p
x^16 = x^8 * x^8 % p
x^17 = x^1 * x^16 % p
递归的实现
long long pow(long long x, long long n, long long p) { if (n == 0) { return 1; } else { int t = pow(x * x % p, n / 2, p); if (n % 2 == 1) { t = t * x % p; } return t; } }
非递归的实现
int pow(int x, int n, int p) { int re = 1; for (; n > 0; n >>= 1) { if (n % 2 == 1) { re = (long long)re * x % p; } x = (long long)x * x % p; } return re; }
x * x % p
越界。(n % 2 == 1)
替换为(n & 1)
。Python语言中的pow函数,可以直接计算整数的快速幂,非常适合用来做手速题。(其实你只需要在自己的模板中实现出快速幂即可)
在一些情况中快速幂的可能非常大。
pow(x, pow(y, n), p)
可以先通过找循环节的方式把指数部分取模pow(x, pow(y, n), p) == pow(x, pow(y, n, p - 1), p)
这个算法对于所有有结合律的运算均可以优化,其他常见的如下
https://www.luogu.com.cn/problem/P1226
给你三个整数 ,求 。
输入只有一行三个整数,分别代表 。
输出一行一个字符串 a^b mod p=s
,其中 分别为题目给定的值, 为运算结果。
2 10 9
2^10 mod 9=7
样例解释
,。
数据规模与约定
对于 的数据,保证 ,,。
#include <bits/stdc++.h> using namespace std; long long gao(long long b, long long p, long long k) {// b的p次方mod k if (p == 0) { return 1 % k; } else if (p % 2 == 0) { long long r = gao(b, p / 2, k); return r * r % k; } else { return gao(b, p - 1, k) * b % k; } } long long b, p, k; int main() { cin >> b >> p >> k; printf("%lld^%lld mod %lld=%lld\n", b, p, k, gao(b, p, k)); return 0; }
快速幂模板题,但是需要考虑很多特殊情况
越界和取模
int 2e9
long long 9e18
底数是1
底数是0
指数是0
指数是负数
模数是1
https://www.luogu.com.cn/problem/P6075
给定 个元素的集合 和整数,现在要从 中选出若干子集 (,)排成下面所示边长为 的三角形(因此总共选出了 个子集)。
此外,JYY 对选出的子集之间还有额外的要求:选出的这些子集必须满足
且 。
JYY 想知道,求有多少种不同的选取这些子集的方法。因为答案很大,JYY 只关心输出答案模 的值。
对于两种选取方案 和 只要存在 满足 ,我们就认为 和 是不同的方案。
输入包含一行两个整数 和 。
一行一个整数,表示不同方案数目模 的值。
2 2
16
对于 的数据,,。
https://www.luogu.com.cn/problem/P3197
监狱有 个房间,每个房间关押一个犯人,有 种宗教,每个犯人会信仰其中一种。如果相邻房间的犯人的宗教相同,就可能发生越狱,求有多少种状态可能发生越狱。
答案对 取模。
输入只有一行两个整数,分别代表宗教数 和房间数 。
输出一行一个整数代表答案。
2 3
6
样例输入输出 1 解释
状态编号 | 1 号房间 | 2 号房间 | 3 号房间 |
---|---|---|---|
1 | 信仰 1 | 信仰 1 | 信仰 1 |
2 | 信仰 1 | 信仰 1 | 信仰 2 |
3 | 信仰 1 | 信仰 2 | 信仰 2 |
4 | 信仰 2 | 信仰 1 | 信仰 1 |
5 | 信仰 2 | 信仰 2 | 信仰 2 |
6 | 信仰 2 | 信仰 2 | 信仰 1 |
数据规模与约定
对于 的数据,保证 ,。
#include <bits/stdc++.h> using namespace std; long long n, m, p = 100003; long long pw(long long x, long long y, long long p) { long long re = 1; for (; y; y >>= 1) { if (y & 1) { re = re * x % p; } x = x * x % p; } return re; } int main() { cin >> m >> n; long long a = pw(m, n, p); long long b = pw(m - 1, n - 1, p) * m % p; cout << (a + p - b) % p << endl; }
全部减去不会发生越狱的。
(pow(m, n, mod) - pow(m - 1, n - 1, mod) * m) % mod
https://en.wikipedia.org/wiki/Greatest_common_divisor
int gcd(int x, int y) {
return y ? gcd(y, x % y) : x;
}
int lcm(int x, int y) {
return x / gcd(x, y) * y;
}
https://www.luogu.com.cn/problem/P1965
个小伙伴(编号从 到 )围坐一圈玩游戏。按照顺时针方向给 个位置编号,从 到 。最初,第 号小伙伴在第 号位置,第 号小伙伴在第 号位置,……,依此类推。游戏规则如下:每一轮第 号位置上的小伙伴顺时针走到第 号位置,第 号位置小伙伴走到第 号位置,……,依此类推,第n - m号位置上的小伙伴走到第 0 号位置,第 号位置上的小伙伴走到第 号位置,……,第 号位置上的小伙伴顺时针走到第 号位置。
现在,一共进行了 轮,请问 号小伙伴最后走到了第几号位置。
共行,包含 个整数,每两个整数之间用一个空格隔开。
个整数,表示 轮后 号小伙伴所在的位置编号。
10 3 4 5
5
对于 的数据,;
对于 的数据,;
对于的数据,。
#include <bits/stdc++.h> using namespace std; int n, m, k, x; long long pw(long long x, long long y, long long p) { long long re = 1; for (; y; y >>= 1) { if (y & 1) { re = re * x % p; } x = x * x % p; } return re; } int main() { cin >> n >> m >> k >> x; cout << (x + m * pw(10, k, n)) % n << endl; }