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;
}
posted @ 2021-12-15 22:13  Eason_AC  阅读(47)  评论(1)    收藏  举报