前言
t
a
g
:
tag :
tag: 前缀和 二分 思维 传送门 :
题意
给定一个数组
a
[
]
a[]
a[],长度
n
n
n
询问有多少种方法,可以使得数组均分成三份
数据范围
n
∈
[
1
,
1
0
5
]
n\in[1,10^5]
n∈[1,105]
思路
根据数据范围,显然是要控制在
n
l
o
g
n
nlogn
nlogn以下的
对于这种题,一开始就想到的是二分,但是如果对和进行二分的话,会发现不满足单调性,因为
a
[
i
]
<
0
a[i]<0
a[i]<0的情况存在
因此不妨换一个方向进行二分
首先我们可以出来
s
u
m
[
i
]
=
=
(
s
u
m
[
n
]
/
3
)
sum[i]==(sum[n]/3)
sum[i]==(sum[n]/3)的下标,用于表示一个分组满足条件的下标
然后我们再处理出来
s
u
m
[
i
]
=
=
2
?
(
s
u
m
[
n
]
/
3
)
sum[i]==2*(sum[n]/3)
sum[i]==2?(sum[n]/3)的下标,用于处理二个分组条件的下标
我们会发现如果前面两个分组定下来了,那么第三个数组也定下来了
因此我们只再 两个分组满足条件的集合中寻找 有多少个 单一分组满足条件
Code
const int N = 1e5+10;
int n;
int s[N];
vector<int> v1,v2;
void solve(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>s[i];
s[i] = s[i-1] + s[i];
}
if(s[n]%3){
cout<<0<<endl;
return;
}
int avg = s[n]/3;
ll res = 0 ;
for(int i=1;i+2<=n;i++)
if(s[i] == avg)
v1.pb(i);
for(int i=2;i+1<=n;i++)
if(s[i] == 2*avg) v2.pb(i);
for(int i=0;i<v1.size();i++){
int pos = upper_bound(all(v2),v1[i])-v2.begin();
res += v2.size()-pos;
}
cout<<res<<endl;
}
|