CF1036D Vasya and Arrays 题解
Content
给定两个长度分别为 \(n\) 和 \(m\) 的数列 \(A,B\)。你需要将两个数列都恰好分成 \(k\) 份,使得两个数列中第 \(i(i\in[1,k])\) 份的元素和对应相等。问是否可行,并在可行的情况下求出最大的 \(k\)。
数据范围:\(1\leqslant n,m\leqslant 3\times 10^5\),\(1\leqslant A_i,B_i\leqslant 10^9\)。
Solution
我们先将两个数列中的所有数的和加起来,记为 \(S_A,S_B\)。显然,如果 \(S_A\neq S_B\),那么显然我们无法满足题目中的要求。
否则,我们采用双指针的方式,每次移动就记录下当前两个序列的前缀和,记为 \(s_A,s_B\)。
- 如果 \(s_A<s_B\),那么我们将数列 \(A\) 在当前位置下往前移一位。
- 如果 \(s_A>s_B\),那么我们将数列 \(B\) 在当前位置下往前移一位。
- 否则,我们将答案加 \(1\)(就相当于在这里把还未分进去的元素分成一份了),然后选择任意一个数列在当前位置下往前移一位。
输出答案即可。复杂度为 \(\mathcal{O}(n)\),足以通过本题。
Code
int a[300007], b[300007], visa[300007], visb[300007], ans;
ll sa, sb, suma, sumb;
int main() {
int n = Rint; F(int, i, 1, n) suma += (a[i] = Rint);
int m = Rint; F(int, i, 1, m) sumb += (b[i] = Rint);
if(suma != sumb) return printf("-1"), 0;
for(int i = 1, j = 1; i <= n && j <= m;) {
sa += 1ll * a[i] * (1 - visa[i]), sb += 1ll * b[j] * (1 - visb[j]), visa[i] = visb[j] = 1; //为了避免重复加入前缀和,开 vis 数组记录当前元素是否已经加入前缀和。
if(sa == sb) ans++, sa = sb = 0, i++;
else if(sa > sb) j++;
else i++;
}
return write(ans), 0;
}

浙公网安备 33010602011771号