洛谷P2381 圆圆舞蹈

P2381 圆圆舞蹈

题目描述

熊大妈的乃修在时针的带领下,围成了一个圆圈舞蹈,由于没有严格的教育,奶牛们之间的间隔不一致。

奶牛想知道两只最远的奶牛到底隔了多远。奶牛A到B的距离为A顺时针走和逆时针走,到达B的较短路程。告诉你相邻两个奶牛件的距离,请你告诉奶牛两只最远的奶牛到底隔了多远。

输入输出格式

输入格式:

第一行一个整数N,表示有N只奶牛。(2<=N<=100000)

接下2-N+1行,第i行有一个数,表示第i-1头奶牛顺时针到第i头奶牛的距离。(1<=距离<=maxlingint,距离和<=maxlongint)

第N+1行的数表示第N头奶牛顺时针到第1头奶牛的距离。

输出格式:

一行,表示最大距离。

输入输出样例

输入样例#1:
Crile.in
5
1
2
3
4
5
输出样例#1:
Crile.out
7


Solution 做法1:
记录前缀和,可知前缀和是递增的,枚举起点,我们不难二分一个"中点"
中点左边的点距离小于半个周长,右边的点距离大于半个周长,然后用终点顺、逆时针距离最小值更新答案即可。
复杂度O(nlogn)

做法2:
记录前缀和sum,总长度Len
于是从第一头奶牛开始,找到l,r两只牛,l <= r 这里从1开始
不难发现当距离小于总长度一半的时候,我们需要去找l, r + 1
当距离大于总长度一半的时候,我们需要去找l + 1, r 一定优于l + 1, r + 1

这样省去了很多无用的l,r
乱搞一下就可以了
复杂度O(n)

Code
第二种做法

#include <bits/stdc++.h>

const int MAXN = 100000 + 10;

inline void read(int &x){x = 0;char ch = getchar();char c = ch;while(ch > '9' || ch < '0')c = ch, ch = getchar();while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar();if(c == '-')x = -x;}
inline void swap(int &a, int &b){int tmp = a;a = b;b = tmp;}
inline int min(int a,int b){return a > b ? b : a;}
inline int max(int a,int b){return a > b ? a : b;}

int n;
int sum[MAXN],num[MAXN],len;
int ans;
int main()
{
	read(n); 
	for(int i = 2;i <= n;i ++)
	{
		read(num[i]);
		sum[i] = sum[i - 1] + num[i];
		len += num[i];
	}
	read(num[1]);len += num[1];sum[n + 1] = sum[n] + num[1];
	int l = 1, r = 1;int mid = len >> 1;
	while(l <= n + 1 && r <= n + 1)
	{
		if(l == r)
		{
			r ++;
		}
		else if(sum[r] - sum[l] <= mid)
		{
			ans = max(ans, sum[r] - sum[l]);
			r ++;
		}
		else if(sum[r] - sum[l] > mid)
		{
			ans = max(ans, min(sum[r] - sum[l], mid - sum[r] + sum[l]));
			l ++;
		}
	}
	printf("%d", ans);
    return 0;
}

 

第一种做法
#include <bits/stdc++.h>

const int MAXN = 300000 + 10;

inline void read(int &x){x = 0;char ch = getchar();char c = ch;while(ch > '9' || ch < '0')c = ch, ch = getchar();while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar();if(c == '-')x = -x;}
inline void swap(int &a, int &b){int tmp = a;a = b;b = tmp;}
inline int min(int a,int b){return a > b ? b : a;}
inline int max(int a,int b){return a > b ? a : b;}

int n;
int sum[MAXN >> 1],len;
int ans;

inline int erfen(int l, int r, int p)
{
	int mid = l + (r - l);
	while(l < r)
	{
		mid = l + ((r - l) >> 1);
		if(p <= sum[mid])r = mid;
		else l = mid + 1;
	}
	return l;
}

//枚举起始点i,二分找j,令s[j] - s[i] <= s / 2  这样j 和 j-1  两个点二选一
//处理环就多复制一层    
int main()
{
	read(n); 
	for(int i = 1;i <= n;i ++)
	{
		read(sum[i]);
		len += sum[i];
		sum[i] += sum[i - 1];
	}
	for(int i = 1;i <= n;i ++)
	{
		 sum[i + n] = len + sum[i];
	}
	for(int i = 1;i <= 2 * n;i ++)
	{
		int tmp = erfen(1, 2 * n, sum[i] + (len >> 1));
		ans = max(ans, min(sum[tmp] - sum[i], len - sum[tmp] + sum[i]));
		ans = max(ans, sum[tmp - 1] - sum[i]) ;
	}
	printf("%d", ans);
    return 0;
}

 






posted @ 2017-06-14 10:30  嘒彼小星  阅读(291)  评论(0编辑  收藏  举报