题目描述
“丢~丢~丢手绢,轻轻地放在小朋友的后面,大家不要告诉她,快点快点抓住她,快点快点抓住她。”
牛客幼儿园的小朋友们围成了一个圆圈准备玩丢手绢的游戏,但是小朋友们太小了,不能围成一个均匀的圆圈,即每个小朋友的间隔可能会不一致。为了大家能够愉快的玩耍,我们需要知道离得最远的两个小朋友离得有多远(如果太远的话牛老师就要来帮忙调整队形啦!)。
因为是玩丢手绢,所以小朋友只能沿着圆圈外围跑,所以我们定义两个小朋友的距离为沿着圆圈顺时针走或者逆时针走的最近距离。
输入描述:
第一行一个整数N,表示有N个小朋友玩丢手绢的游戏。
接下来的第2到第n行,第i行有一个整数,表示第i-1个小朋友顺时针到第i个小朋友的距离。
最后一行是第N个小朋友顺时针到第一个小朋友的距离。
输出描述:
输出一个整数,为离得最远的两个小朋友的距离。
输入
3 1 2 3
输出
3
备注:
2≤N≤100000 距离和(圆圈周长)小于等于2147483647
———————————————————————————————————————————
题解:
方法一:
要注意两个小朋友的距离为沿着圆圈顺时针走或者逆时针走的最近距离(劣弧),首先选取一个小朋友作为起点,那么距离他最远的小朋友一定在他这条直径的对面的两个小朋友中的一个(一个大于周长的一半,一个是小于周长的一半的最接近的一个)。假设我们先只讨论大于周长的一半的那个,把他看作最远距离的那一个,在后来的循环中总会讨论到没有被选择的那个小朋友,那么那个小朋友由于我们也只讨论大于周长的一半的那个,如果他们之间没有更优选择,我们最后选择的就会是那个起点小朋友,那么这个在前面没有被选择的情况在这里就被讨论到了,但如果有更优选择,那么这个没有被选择的情况就更不可能是答案了,也就不需要讨论。
这里需要注意如果我们开的周长是int型,那么周长的一半会直接舍去余数,也就是我们以为的周长的一半实际上没有到达周长的一半,所以选择的大于周长的一半的那个孩子很有可能没有到达周长的一半,所以不可以直接周长-距离,这样得到的距离可能是那段优弧。
#include<iostream>
using namespace std;
int a[100005];
int main(){
int n,i,l=1,r=1,sum=0,ans=0,Len=0,L;
cin>>n;
for(i=1;i<=n;i++){
cin>>a[i];
Len+=a[i];
}
a[0]=a[n];
L=Len/2;
for(l=1;l<=n;l++){
while(sum<L){
sum+=a[r%n];
r++;
}
ans=max(ans,min(sum,Len-sum));
sum-=a[l];
}
cout<<ans;
return 0;
}
方法二:
其实也可以直接把两种情况一次讨论完,先找到那个大于周长的一半,这个比找小于周长的一半的那个简单,我们通过他把右指针往前减一个,那么找到的就是小于周长的一半的那个。但这时候我们要把周长开成double型,不然如果找到的大于周长的一半实际上没有大于周长的一半,那么紧接着找到的小于周长的一半的那个也是错的。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int i,j,n,s[100010];
double sum=0,mid;
cin>>n;
for(i=0;i<n;i++)
{
cin>>s[i];
sum+=s[i];
}
mid=sum/2;
int t=0,ans=0;
for(i=0,j=0;i<n;i++)
{
while(t<mid)
{
t+=s[j++%n];
}
int s1=sum-t;
int s2=t-s[(j-1+n)%n];
s1=max(s1,s2);//看这两个小朋友谁的距离更远
ans=max(ans,s1);
t-=s[i];
}
cout<<ans<<endl;
return 0;
}