1 条题解
-
0
矩阵和模最大值问题题解
这个问题涉及到一个三维矩阵中的模运算优化,主要考察前缀和数组、二分查找和集合操作的综合应用。
问题分析
问题描述: 给定一个3行N列的矩阵,每列有三个值。要求找到一个分割点k,使得以下表达式的值最大:
(S1[k] - S2[k-1]) mod M + (S3[N] - S3[k-1] + S2[k]) mod M
其中S1、S2、S3分别是三行的前缀和数组,M是给定的模数。
关键思路:
- 预处理三行的前缀和数组
- 枚举分割点k,维护一个集合存储前面所有k的(S1[k] - S2[k-1]) mod M值
- 对于每个k,在集合中查找使得第二个表达式值最大的元素
解题思路
-
前缀和数组:
- 计算每行的前缀和数组,其中pre[i][j]表示第i行前j个元素的和模M的值
-
枚举分割点:
- 对于每个分割点k,计算两个关键值:
- x1 = (pre[1][k] - pre[2][k-1]) mod M
- x2 = (pre[3][N] - pre[3][k-1] + pre[2][k]) mod M
- 对于每个分割点k,计算两个关键值:
-
集合优化:
- 使用一个有序集合维护所有前面计算过的x1值
- 对于每个x2,在集合中查找小于等于(mod - x2)的最大元素,以最大化(x2 + y) mod M
代码实现分析
关键数据结构:
const int MAXN = 100100; long long mz[5][MAXN], pre[5][MAXN]; // 存储矩阵和前缀和数组 set<long long> st; // 维护x1值的有序集合
前缀和计算:
pre[1][0] = pre[2][0] = pre[3][0] = 0; for(i = 1; i <= 3; i++) for(j = 1; j <= n; j++) pre[i][j] = (mz[i][j] + pre[i][j-1]) % mod;
枚举分割点并维护集合:
st.clear(); ans = 0; for(i = 1; i <= n; i++) { x1 = (pre[1][i] - pre[2][i-1] + mod) % mod; st.insert(x1); // 将当前x1加入集合 x2 = (pre[3][n] - pre[3][i-1] + pre[2][i] + mod) % mod; it = st.lower_bound(mod - x2); // 查找第一个不小于(mod - x2)的元素 ans = max(ans, (x2 + *(--it)) % mod); // 取前一个元素,计算最大值 }
主函数处理流程:
int main() { long long n, mod, i, j, ans, x1, x2; while(~scanf("%lld%lld", &n, &mod)) { // 读取矩阵 for(i = 1; i <= 3; i++) for(j = 1; j <= n; j++) scanf("%lld", &mz[i][j]); // 计算前缀和 // ... // 枚举分割点并计算最大值 // ... printf("%lld\n", ans); } }
复杂度分析
- 时间复杂度:,其中N是矩阵的列数。主要是枚举每个分割点并在集合中进行查找操作。
- 空间复杂度:,主要用于存储前缀和数组和集合。
这个算法通过预处理前缀和数组和使用有序集合快速查找最优解,高效地解决了问题。集合的lower_bound操作确保了每次查找的时间复杂度为O(log N),使得整体算法能够处理较大的输入规模。
- 1
信息
- ID
- 625
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者