AtCoder Beginner Contest 265 D Iroha and Haiku (New ABC Edition)

\(O{(n\log n)}\) 做法
我在考场上只想到此做法,不难想到,可以将三段用二分预处理。
\(xs[i]\)表示从\(a_i\)开始总和为\(P\)的末尾编号,可以用二分处理。
最后 \(O(n)\) 判断即可。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll N=2e5+5;
const ll INF=0x3f3f3f3f;
ll n,x,y,z;
ll a,s[N];
ll xs[N],ys[N],zs[N];
int main(){
scanf("%lld%lld%lld%lld",&n,&x,&y,&z);
for(ll i=1;i<=n;i++){
scanf("%lld",&a);
s[i]=s[i-1]+a;
}
for(ll i=1;i<=n;i++){
ll l=i,r=n;
while(l<=r){
ll mid=(l+r)/2;
ll num=s[mid]-s[i-1];
if(num>x) r=mid-1;
else if(num<x) l=mid+1;
else{
l=mid;
break;
}
}
ll num=s[l]-s[i-1];
if(num==x) xs[i]=l;
else xs[i]=INF;
}
for(ll i=1;i<=n;i++){
ll l=i,r=n;
while(l<=r){
ll mid=(l+r)/2;
ll num=s[mid]-s[i-1];
if(num>y) r=mid-1;
else if(num<y) l=mid+1;
else{
l=mid;
break;
}
}
ll num=s[l]-s[i-1];
if(num==y) ys[i]=l;
else ys[i]=INF;
}
for(ll i=1;i<=n;i++){
ll l=i,r=n;
while(l<=r){
ll mid=(l+r)/2;
ll num=s[mid]-s[i-1];
if(num>z) r=mid-1;
else if(num<z) l=mid+1;
else{
l=mid;
break;
}
}
ll num=s[l]-s[i-1];
if(num==z) zs[i]=l;
else zs[i]=INF;
}
for(ll i=1;i<=n;i++){
if(xs[i]>=n) continue;
if(xs[i]==INF) continue;
if(ys[xs[i]+1]>=n) continue;
if(ys[xs[i]+1]==INF) continue;
if(zs[ys[xs[i]+1]+1]==INF) continue;
printf("Yes");
return 0;
}
printf("No");
return 0;
}
\(O{(n)}\) 做法
不难发现,以上做法是有点浪费的,每个节点需分别计算,其实可以线性\(O(n)\)一次计算出\(n\)个节点。
添加一个指针,如果区间里的值小于目标值,则指针往右移。
因为指针最多移\(n\)次,所以这个算法是线性的。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll N=2e5+5;
const ll INF=0x3f3f3f3f;
ll n,x,y,z,xp,yp,zp;
ll a,s[N];
ll xs[N],ys[N],zs[N];
int main(){
scanf("%lld%lld%lld%lld",&n,&x,&y,&z);
for(ll i=1;i<=n;i++){
scanf("%lld",&a);
s[i]=s[i-1]+a;
}
for(ll i=1;i<=n;i++){
while(xp<n&&s[xp]-s[i-1]<x) xp++;
if(s[xp]-s[i-1]==x) xs[i]=xp;
else xs[i]=INF;
}
for(ll i=1;i<=n;i++){
while(yp<n&&s[yp]-s[i-1]<y) yp++;
if(s[yp]-s[i-1]==y) ys[i]=yp;
else ys[i]=INF;
}
for(ll i=1;i<=n;i++){
while(zp<n&&s[zp]-s[i-1]<z) zp++;
if(s[zp]-s[i-1]==z) zs[i]=zp;
else zs[i]=INF;
}
for(ll i=1;i<=n;i++){
if(xs[i]>=n) continue;
if(xs[i]==INF) continue;
if(ys[xs[i]+1]>=n) continue;
if(ys[xs[i]+1]==INF) continue;
if(zs[ys[xs[i]+1]+1]==INF) continue;
printf("Yes");
return 0;
}
printf("No");
return 0;
}

浙公网安备 33010602011771号