喵哈哈村的嘟嘟熊魔法(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");
}
}