CSUOJ 1956 数字和

Description

长者对小明施加了膜法,使得小明每天起床就像马丁的早晨一样。 今天小明早上起来后发现身体虽然变小,头脑依旧不变变傻。

他有一条纸带,上面有n个数字,第i个数字为Ai。 他想把纸带选三个位置p1, p2, p3(p1 < p2 < p3)把纸带剪成4个每条长度至少为1的4条纸带。 分别为[1, p1-1], [p1+1, p2-1], [p2+1, p3-1], [p3+1, n],使得4个部分中数字之和相等。

Input

多组输入 每组测试数据第一行输入一个n(7 ≤ n ≤ 105) 第二行n个数,第i个数为Ai(0 ≤ Ai ≤ 109),表示第i个数

Output

输出字典序最小的p1,p2,p3 如果不存在这种操作,输出-1

Sample Input

7
6 2 6 2 6 2 6
7
1 2 3 4 5 6 7

Sample Output

2 4 6
-1

Hint

思路:使用尺取,详细看代码
#include
#include
#include
#include
using namespace std;
#define MAXN 100010
#define INF 0x3fffffff
int a[MAXN],sum[MAXN];
int p1, p2, p3;
int slove(int n)
{
	p1 = 2; p2 = 4; p3 = 6;//p1,p2,p3代表四个区间的中间位置
	for (; p1 <= n; p1++)//不断更新p1的位置
	{
		p2 = max(p2, p1 + 2);
		while (p2 <= n&&sum[p1 - 1] > sum[p2 - 1] - sum[p1])//如果第二个区间的值小于第一个区间的值
			p2++;
		if (p2 >= n|| sum[p1 - 1] < sum[p2 - 1] - sum[p1])//如果第二个区间的值大于第一个区间的值就跳过
			continue;
		p3 = max(p3, p2 + 2);
		while (p3 <= n&&sum[p1 - 1]>sum[p3 - 1] - sum[p2]) p3++;//判断第三个区间的值与第一个区间的值的大小关系
		if (p3 >= n || sum[p3 - 1] - sum[p2]>sum[p1 - 1])
			continue;
		if (sum[n] - sum[p3] == sum[p1 - 1])//判断第四个区间
		{
			cout << p1 << ' ' << p2 << ' ' << p3 << endl;
			return 1;
		}
	}
	return 0;
}
int main()
{
	int n;
	while (cin>>n)
	{
		for (int i = 1; i <= n; i++)
		{
			cin >> a[i];
			sum[i] = sum[i - 1] + a[i];
		}
		if (!slove(n))
			cout << "-1" << endl;
	}
}
/**********************************************************************
	Problem: 1956
	User: leo6033
	Language: C++
	Result: AC
	Time:788 ms
	Memory:2804 kb
**********************************************************************/

你可能感兴趣的:(CSUOJ 1956 数字和)