圆圈舞蹈
【问题描述】
熊大妈的奶牛在时针的带领下,围成了一个圆圈跳舞。由于没有严格的教育,奶牛们之间的间隔不一致。
奶牛想知道两只最远的奶牛到底隔了多远。奶牛A到B的距离为A顺时针走和逆时针走,到达B的较短路程。告诉你相邻两个奶牛间的距离,请你告诉奶牛两只最远的奶牛
到底隔了多远。
【输入】
第一行一个整数N,表示有N只奶牛。(2≤N≤100000)
接下来2~N+1行,第I行有一个数,表示第I-1头奶牛顺时针到第I头奶牛的距离。(1≤距离≤maxlongint,距离和≤maxlongint)
第N+l行的数表示第N头奶牛顺时针到第1头奶牛的距离。
【输出】
一行,表示最大距离。
暴力算法我就不打了 应该能过一些数据
二分算法
用前缀和将环一分为二,再枚举答案。
大概二分是一个很咸的东西啦
把这个圆顺时针做前缀和,肯定越对面距离越大,然后枚举两边的值并比较即可
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int sum[200010],a[200010],n,l,r,x,mid,y,maxx,minx,tmp;
int main()
{
freopen("circle.in","r",stdin);
freopen("circle.out","w",stdout);
scanf("%d",&n);
for (int i=2; i<=n+1; i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
for (int i=n+2; i<=2*n; i++)
sum[i]=sum[n+1]+sum[i-n];
maxx=0;
for (int i=1; i<=n; i++)
{
l=i; r=n+i;
minx=2147000000;
while (l<=r)
{
mid=(l+r)>>1;
x=sum[mid]-sum[i];
y=sum[n+i]-sum[mid];
if (fabs(x-y)<minx)
{
minx=fabs(x-y);
if (x<y) tmp=x; else tmp=y;
if (tmp>maxx) maxx=tmp;
}
if (l==mid) break;
if (x<y) l=mid; else r=mid;
}
x=sum[r]-sum[i];
y=sum[n+i]-sum[r];
if (fabs(x-y)<minx)
{
minx=fabs(x-y);
if (x<y) tmp=x; else tmp=y;
if (tmp>maxx) maxx=tmp;
}
}
cout<<maxx;
}
o(n)算法
我觉得这个还是蛮微妙的
emmm
可以把这个圆看作一条直线
设立一个l,一个r分别指向这条直线,l到r之间的距离为x
那么最右值肯定是越靠近总和除以2越好
1 2 3 4 5 … n
l r
那么,当x小于sum/2时,r往右靠,(一遍做一边打擂),如果x大于sum/2,那么l向右靠,当r到n时,循环结束,答案得出
是是不是有点神奇!!
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
long long n,sum=0,ans=0;
long long a[100100];
int main()
{
freopen("circle.in","r",stdin);
freopen("circle.out","w",stdout);
scanf("%lld",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]),a[i]+=a[i-1];
sum=a[n];
int l=1,r=2;
while(l<r && r<=n)
{
long long res1=a[r]-a[l],res2=sum-res1;
ans=max(ans,min(res1,res2));
if(res1>res2) l++;
else r++;
}
printf("%lld",ans);
fclose(stdin);
fclose(stdout);
return 0;
}