喵哈哈村的嘟嘟熊魔法(四)(set+对组)

探讨通过枚举中间切点并利用前缀和与后缀和来判断能否将一组数字序列等分为四个子序列的问题。该算法适用于解决特定类型的数字序列分割挑战。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

喵哈哈村的嘟嘟熊魔法(4)

发布时间: 2017年3月5日 16:01   最后更新: 2017年3月5日 16:04   时间限制: 1000ms   内存限制: 128M

百度是喵哈哈村的赞助商,所以百度派出了嘟嘟熊给大家展现魔法:

“抽刀断水水更流,举杯消愁愁更愁。”

只见刹那间,嘟嘟熊就从兜里面掏出了一堆数字,这一堆数字仿佛有了生命,不停的在空气中跃动。

这些数字排成一排。

嘟嘟熊又从兜里面拿出了三把大刀,欲将这些数字斩断,连续三刀斩成四节,使得每一节的和都一样,且每一节的长度至少大于0。

比如数组A={2,5,1,1,1,1,4,1,7,3,7},就可以把下标为2,7,9的斩断,就变成了{2,5},{1,1,1,4},{7},{7},每一节的和都一样。

但是对于数组A={10,2,11,13,1,1,1,1,1},就不存在可以使得四节的和相同的方案。

本题包含若干组测试数据。
第一行一个n,表示有n个数字。
第二行n个整数a[i]。

保证 1<=n<=100000,-100000<=a[i]<=100000

如果可行的话,输出Yes,否则输出No

  复制
11
2 5 1 1 1 1 4 1 7 3 7
9
10 2 11 13 1 1 1 1 1
Yes
No


题目:http://qscoj.cn/problem/28/

题解:http://www.cnblogs.com/qscqesze/p/6505271.html


方法:

枚举中间的切点mid,然后判断左右两边是否都存在一个切点l,r使得正好平分

对于切点l,一定满足sum[l-1]==sum[mid-1]-sum[l],即sum[l-1]+sum[l]==sum[mid-1],其中sum[i]为前缀和

对于切点r,求一波后缀和sum'[],之后同理

如果对于某个当前中间切点mid,存在切点l和r,且sum[l-1]==sum'[r+1],那么就说明可以满足题目要求

开两个set,一个存对组pair(first, second),其中first表示sum[l-1]+sum[l](也就是sum[mid-1])

second表示s[l-1](也就是切割后每个小区间的和)

另一个存答案,ans[i]中的元素全部是左半部分能切出来的小区间和

那么在找右边的切点r的时候,只需要判断切出的小区间和是否在ans[i]中出现即可!


#include<stdio.h>
#include<set>
#include<algorithm>
using namespace std;
#define LL long long
set<pair<LL, LL> > S;
set<LL> ans[100005];
LL n, a[100005], b[100005];
int main(void)
{
	int i, ok;
	set<pair<LL, LL> >::iterator it;
	while(scanf("%lld", &n)!=EOF)
	{
		for(i=1;i<=n;i++)
		{
			scanf("%lld", &a[i]);
			b[i] = b[i-1]+a[i];
			ans[i].clear();
		}
		S.clear();
		for(i=4;i<=n;i++)
		{
			S.insert(make_pair(b[i-2]+b[i-3], b[i-3]));
			it = S.lower_bound(make_pair(b[i-1], -10000000));
			while(it!=S.end() && (*it).first==b[i-1])
			{
				ans[i].insert((*it).second);
				it++;
			}
		}
		S.clear();
		ok = 0;
		for(i=n;i>=1;i--)
			b[i] = b[i+1]+a[i];
		for(i=n-3;i>=1;i--)
		{
			S.insert(make_pair(b[i+2]+b[i+3], b[i+3]));
			it = S.lower_bound(make_pair(b[i+1], -10000000));
			while(it!=S.end() && (*it).first==b[i+1])
			{
				if(ans[i].find((*it).second)!=ans[i].end())
					ok = 1;
				it++;
			}
		}
		if(ok==1)
			printf("Yes\n");
		else
			printf("No\n");
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值