Make Nonzero Sum (hard version)

You are given an array [a1,a2,…an][a1,a2,…an] consisting of integers −1−1, 00 and 11. You have to build a partition of this array into the set of segments [l1,r1],[l2,r2],…,[lk,rk][l1,r1],[l2,r2],…,[lk,rk] with the following property:

  • Denote the alternating sum of all elements of the ii-th segment as sisi: sisi = ali−ali+1+ali+2−ali+3+…±ariali−ali+1+ali+2−ali+3+…±ari. For example, the alternating sum of elements of segment [2,4][2,4] in array [1,0,−1,1,1][1,0,−1,1,1] equals to 0−(−1)+1=20−(−1)+1=2.
  • The sum of sisi over all segments of partition should be equal to zero.

Note that each sisi does not have to be equal to zero, this property is about sum of sisi over all segments of partition.

The set of segments [l1,r1],[l2,r2],…,[lk,rk][l1,r1],[l2,r2],…,[lk,rk] is called a partition of the array aa of length nn if 1=l1≤r1,l2≤r2,…,lk≤rk=n1=l1≤r1,l2≤r2,…,lk≤rk=n and ri+1=li+1ri+1=li+1 for all i=1,2,…k−1i=1,2,…k−1. In other words, each element of the array must belong to exactly one segment.

You have to build a partition of the given array with properties described above or determine that such partition does not exist.

Note that it is not required to minimize the number of segments in the partition.

Input

Each test contains multiple test cases. The first line contains the number of test cases tt (1≤t≤100001≤t≤10000). Description of the test cases follows.

The first line of each test case contains an integer nn (1≤n≤2000001≤n≤200000) — the length of array aa.

The second line of each test case contains nn integers a1,a2,…,ana1,a2,…,an (aiai is −1−1, 00, or 11) — the elements of the given array.

It's guaranteed that the sum of nn over all test cases does not exceed 200000200000.

Output

For each test case print an integer kk — the number of segments in the partition. If required partition does not exist, print −1−1.

If partition exists, in the ii-th of the following kk lines print two integers lili and riri — description of the ii-th segment. The following conditions should be satisfied:

  • li≤rili≤ri for each ii from 11 to kk.
  • li+1=ri+1li+1=ri+1 for each ii from 11 to (k−1)(k−1).
  • l1=1,rk=nl1=1,rk=n. 

If there are multiple correct partitions of the array, print any of them.

 题意:

       给定由0,1,-1构成的序列,将它们分组使得最后总和为0(每一组的和并不一定为0)。成组的序列按照a[l]-a[l+1]+a[l+2]-....-a[r-1]+a[r]的规则进行运算。如果有多组答案,只需输出其中一组。

分析:

      1.首先,易证如果所有数累加和为奇数,则无解。

      2.若累加和num为0,则单独成组即可。

      3.当num不为0时,以num大于0为例,则必然是1多了,需要减少正贡献。观察发现分组[0, 1], [1, 1], [-1, 1]三种情况都可以使序列之和-2。因此,只要找到num/2个这样的组合即可使得序列和为0。考虑所有1都挨在一起的边界情况,此时恰有num/2组[*, 1],由此可得此种解法可行。

      4.num小于0时同理。

#include<iostream>
#include<cmath>
#include<vector>
using namespace std;

typedef pair<int, int> PII;
const int N = 2e5 + 5;
int a[N], n, num;

void MakeNoneZeroSum(int k) {

	vector<PII> res;  //记录结果
	int cnt_n = 0;   //记录已成调和组数

	for(int i = 1; i <= n; i ++) {
		if(cnt_n < abs(num/2) && a[i+1] == k) {  //当组数未达到且满足要求
			++ cnt_n;
			res.push_back({i, i+1});
			i ++;
		} else {
			res.push_back({i, i});
		}
	}

	cout << res.size() << endl;
	for(auto tmp: res)
		cout << tmp.first << ' ' << tmp.second << endl;
}

int main() {
	int t;
	cin >> t;
	while(t --) {
		cin >> n;

		num = 0;
		for(int i = 1; i <= n; ++ i) {
			cin >> a[i];
			num += a[i];
		}

		if(abs(num) % 2) {
			cout << -1 << endl;
			continue;
		}

		if(num == 0) {
			cout << n << endl;
			for(int i = 1; i <= n; ++ i)
				cout << i << ' ' << i << endl;
		} 
		else if(num > 0) MakeNoneZeroSum(1);
		else  MakeNoneZeroSum(-1);
	}

	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值