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; }