这道题目考察的是**差分数组(Difference Array)与数论(GCD性质)**的结合。
核心思路
- 分解问题:
- 题目中所有的操作都是乘以
或 。这意味着数组中的每个数字 最终都可以表示为 的形式。 - 求整个序列的最大公约数(GCD),等价于求序列中所有数字在质因数分解后,各质因子指数的最小值。
- 即:
。
- 题目中所有的操作都是乘以
- 转化操作:
- 由于是对指数求最小值,我们可以将区间乘法转化为区间加法。
- 当操作是
l r 2时,相当于区间内所有数字的质因子 的指数加 。 - 当操作是
l r 3时,相当于区间内所有数字的质因子 的指数加 。
- 使用差分数组:
- 由于涉及大量的区间修改,使用差分数组可以将区间操作的时间复杂度从
降为 。 - 我们需要两个差分数组:
diff2维护质因子的指数变化, diff3维护质因子的指数变化。 - 修改:对于区间
加 ,执行 diff[l]++和diff[r+1]--。 - 还原:最后对差分数组求前缀和,即可得到每个位置的实际指数值。
- 由于涉及大量的区间修改,使用差分数组可以将区间操作的时间复杂度从
- 计算结果:
- 遍历还原后的数组,分别找到
的指数最小值和 的指数最小值。 - 利用快速幂计算最终模
的结果。
- 遍历还原后的数组,分别找到
C++ 代码实现
C++
#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>
using namespace std;
const int MOD = 998244353;
// 快速幂函数,计算 (base^exp) % MOD
long long qpow(long long base, long long exp) {
long long res = 1;
while (exp > 0) {
if (exp % 2 == 1) res = (res * base) % MOD;
base = (base * base) % MOD;
exp /= 2;
}
return res;
}
void solve() {
int n, m;
cin >> n >> m;
// 定义两个差分数组,分别记录2的指数和3的指数
// 大小设为 n+2 防止 r+1 越界
vector<int> diff2(n + 2, 0);
vector<int> diff3(n + 2, 0);
for (int i = 0; i < m; ++i) {
int l, r, x;
cin >> l >> r >> x;
if (x == 2) {
diff2[l]++;
diff2[r + 1]--;
} else if (x == 3) {
diff3[l]++;
diff3[r + 1]--;
}
}
// 计算2的指数的最小值
int min_exp2 = INT_MAX;
int current_exp2 = 0;
// 计算3的指数的最小值
int min_exp3 = INT_MAX;
int current_exp3 = 0;
// 遍历1到n,利用前缀和还原每个位置的指数,并同时维护最小值
for (int i = 1; i <= n; ++i) {
current_exp2 += diff2[i];
min_exp2 = min(min_exp2, current_exp2);
current_exp3 += diff3[i];
min_exp3 = min(min_exp3, current_exp3);
}
// 计算最终结果: (2^min_exp2 * 3^min_exp3) % MOD
long long ans = (qpow(2, min_exp2) * qpow(3, min_exp3)) % MOD;
cout << ans << endl;
}
int main() {
// 优化输入输出效率
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
代码详解
-
数据结构:
使用 vector
diff2 和 diff3。大小设为 是为了处理 -based 索引以及差分数组在 处的边界情况,避免越界。 -
差分更新:
C++
diff2[l]++; diff2[r + 1]--;这是标准的差分操作。如果题目输入是
1 5 2,表示第1到第5个数都乘以2(指数+1),我们在diff2[1]加1,在diff2[6]减1。 -
还原与求最值:
在 for 循环中,current_exp2 += diff2[i] 实际上就是在做前缀和。
- 第
个位置实际的 的指数 。 - 我们在计算前缀和的过程中直接取
min,避免了先存储整个数组再遍历一遍,节省空间和时间。
- 第
-
快速幂:
由于指数可能很大(最大可达
),直接计算 会溢出,必须使用快速幂并在每一步进行取模运算。
复杂度分析
- 时间复杂度:
- 处理
次操作: 。 - 还原数组并找最小值:
。 - 快速幂计算:
。 - 总复杂度:
。对于 的数据量,这完全可以在1秒内运行完成。
- 处理
- 空间复杂度:
- 使用了两个长度为
的数组,复杂度为 。
- 使用了两个长度为
这个解法完美契合题目的“差分”提示,且逻辑清晰高效。