每日闲聊
小鹿五命了.
麻了麻了.
题目大意
给定一个序列,求将该序列分割为三段连续的子序列,其和相等的方案数.
给定数据
第一行为
n
n
n,表示序列长度.
第二行给定的序列
A
A
A,每个元素为
A
i
A_i
Ai.
对于每个
A
i
A_i
Ai,
∣
A
i
∣
≤
1
0
4
|A_i| \leq 10^4
∣Ai∣≤104且
A
i
A_i
Ai为整数
输出要求
输出将给定序列分割为三段连续的且所含元素之和相等子序列的方案数.
解题思路
首先奥,如果 ∑ A i \sum A_i ∑Ai不是3的倍数,那就不可能将它分成和相等的三个连续子序列.
int main() {
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d",&a);
sum[i]=sum[i-1]+a;
}
if(sum[n]%3!=0){
puts("0");
return 0;
}
过了这一关之后,我们就知道了要分割的每个子序列的和.
int pos=sum[n]/3;
再去找每个前缀和为 p o s 和 p o s × 2 pos和pos \times 2 pos和pos×2的位置.
for(int i=1;i<n;++i){
if(sum[i]==pos)
t1[++cnt1]=i+1;
if(sum[i]==pos*2)
t2[++cnt2]=i+1;
}
如果我们能在
t
1
t_1
t1中找到
i
i
i,
t
2
t_2
t2中找到
j
j
j,且
i
<
j
i<j
i<j,就有了一个答案.
我们可以先遍历
t
1
t_1
t1,再利用upper_bound
在
t
2
t_2
t2中找符合要求的
j
j
j的数量.
代码奉上.
蒟蒻的AC代码
#include<bits/stdc++.h>
#define N 100005
using namespace std;
int n,a;
int sum[N];
int t1[N],cnt1;
int t2[N],cnt2;
int main() {
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d",&a);
sum[i]=sum[i-1]+a;
}
if(sum[n]%3!=0){
puts("0");
return 0;
}
int pos=sum[n]/3;
for(int i=1;i<n;++i){
if(sum[i]==pos)
t1[++cnt1]=i+1;
if(sum[i]==pos*2)
t2[++cnt2]=i+1;
}
long long ans = 0;
for(int i=1;i<=cnt1;++i){
register int *p=upper_bound(t2+1,t2+1+cnt2,t1[i]);
ans+=(t2+cnt2-p+1);
}
printf("%lld\n",ans);
return 0;
}