第一题
中文题意:求解 n! % m
n:[1,1e9],m:[1,2e4],如果直接循环求解,显然会超时。
那么注意:
当 n >= m 时,n!% m = 1 * 2 * 3 * ... * m * m + 1 * m + 2 * ... * n % m = 0,
当n < m时,直接循环求解即可,
注意循环的过程取模m。
核心代码如下:
void solve() {
cin >> n >> m;
if (n >= m) cout << 0;
else {
int ans = 1;
for (int i = 1; i <= n; i++)
ans = ans * i % m;
cout << ans;
}
}
第二题
中文题意——
给你n个数,要求必须去掉其中一个数,然后对剩下的n-1个数求解gcd,使gcd最大。
解法——
我们先思考一下暴力解法:
枚举每个数,表示删除这个数,然后对于剩下的n-1个数进行gcd求解,不断保留或更新最大值,
很显然,枚举的时间复杂度是O(n),循环遍历剩下的n-1个数,时间复杂度是O(n - 1),求解gcd的时间复杂度是O(logx),由于1 <= n <= 1e6,显然会超时。
那么尝试优化:
已知:对于n个数,求解其gcd,与这n个数的顺序无关,比如{1,2,3,4,5}求解gcd,和{5,4,3,2,1}求解gcd,最终结果一定是相同的。
那么,我们可以从前到后扫一遍数组,求一下前缀gcd,再从后到前扫一遍数组,求一下后缀gcd,然后再从前到后扫一遍数组,这时的循环是枚举删除的数字,根据上面预处理出来的前缀gcd和后缀gcd,即可求出来删除该数字后剩下n-1个数的gcd,并不断保留或更新最大值。
时间复杂度分析:
前缀gcd:O(nlogx)
后缀gcd:O(nlogx)
枚举删除: O(nlogx)
并不会超时,并且显然是这道题的最优解法。
核心代码——
int gcd(int x, int y) {
return y == 0 ? x : g