题目描述
游游有一个2行L列的矩阵),矩阵中的每个元素都≤109,她想知道有多少个2×2的子矩阵中,4个元素恰好有2种不同的元素?
由于列数L≤1012,矩阵的两行用游程编码的方式给出。
例如[(10,2),(20,1),(10,3)]表示数组[10,10,20,10,10,10]。数据的输入格式如下:
-
第一行输入L,N1和N2分别表示两个数组的长度以及数组a的连续段数、数组b的连续段数。
-
接下来N1行输入数组a每段的二元组压缩形式。
-
再接下来N2行输入数组b每段的二元组压缩形式。
输入样例
8 4 3
1 2
3 2
2 3
3 1
1 4
2 1
3 3
输出样例
5
算法
双指针
这道题可以说就是 AtCoder ABC294E 的改编,连样例都一样。思路是类似的,一个指针i指向矩阵第一行a的首元素,另一个指针j指向矩阵第二行b的首元素。
还是和之前一样,哪个段的右端点更靠左,就把哪个段往右移动。下面分析一下什么情况下会产生只有两种数值的2×2子矩阵:
-
如果第一行的第i段[l1,r1]与第二行的第j段[l2,r2]值是相同的,那只有可能在边界的时候产生两种值:(1) 若r1≠r2,在右边界处会产生一个仅有两种元素的2×2矩阵。(2) 否则r1=r2,只有在r1<L,且grid[1][r1+1]=grid[2][r2+1]时才会在右边界处产生一个仅有两种元素的2×2矩阵。
-
如果第一行的第i段[l1,r1]与第二行的第j段[l2,r2]值不相同,且它们的公共段长度len=min(r1,r2)−max(l1,l2)+1≥2,则会产生len−1个仅有两种元素的2×2矩阵。然后考虑边界:(1) 若r1<r2,在grid[1][r1+1]=grid[2][r2]时就会产生一个仅有两种元素的2×2矩阵。(2) 同理,若r1>r2,在grid[2][r2+1]=grid[1][r1]时就会产生一个仅有两种元素的2×2矩阵。(3) 否则r1=r2,只有在grid[1][r1+1]=grid[2][r2]且grid[2][r2+1]=grid[1][r1]时才会在右边界产生一个仅有两种元素的2×2矩阵。
复杂度分析
时间复杂度
双指针算法遍历的是矩阵两行中相同值的段数,因此时间复杂度为O(N1+N2),是线性的。
空间复杂度
仅用空间用来存储题目的输入信息,在算法运行时只使用了几个有限的变量,因此额外空间复杂度为O(1)。
C++ 代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long LL;
typedef pair<int, LL> PIL;
LL l;
int n1, n2;
int main() {
scanf("%lld%d%d", &l, &n1, &n2);
vector<PIL> i1, i2;
for(int i = 1; i <= n1; i++) {
int vi;
LL li;
scanf("%d%lld", &vi, &li);
i1.push_back({vi, li});
}
for(int i = 1; i <= n2; i++) {
int vi;
LL li;
scanf("%d%lld", &vi, &li);
i2.push_back({vi, li});
}
LL ans = 0;
LL p1 = 1, p2 = 1;
int i = 0, j = 0, n = i1.size(), m = i2.size();
while(i < n && j < m) {
int v1 = i1[i].first, v2 = i2[j].first;
LL l1 = p1, r1 = l1 + i1[i].second - 1;
LL l2 = p2, r2 = l2 + i2[j].second - 1;
if(v1 != v2) {
int len = min(r1, r2) - max(l1, l2) + 1;
ans += max(0, len - 1);
if(r1 < r2) {
p1 += i1[i++].second;
if(i < n && i1[i].first == v2) ans++;
}else if(r1 > r2) {
p2 += i2[j++].second;
if(j < m && i2[j].first == v1) ans++;
}else {
p1 += i1[i++].second;
p2 += i2[j++].second;
if(i < n && i1[i].first == v2 && j < m && i2[j].first == v1) ans++;
}
}else {
if(r1 < r2) {
p1 += i1[i++].second;
}else if(r1 > r2) {
p2 += i2[j++].second;
}else {
p1 += i1[i++].second;
p2 += i2[j++].second;
}
if(r1 != r2) {
ans++;
}else {
if(i < n && j < m && i1[i].first == i2[j].first) ans++;
}
}
}
printf("%lld\n", ans);
return 0;
}