[Codeforces Round #320 (Div. 2) -E. Weakness and Poorness (三分/二分)
E. Weakness and Poorness
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
You are given a sequence of n integers a1, a2, ..., a**n.
Determine a real number x such that the weakness of the sequence a1 - x, a2 - x, ..., a**n - x is as small as possible.
The weakness of a sequence is defined as the maximum value of the poorness over all segments (contiguous subsequences) of a sequence.
The poorness of a segment is defined as the absolute value of sum of the elements of segment.
Input
The first line contains one integer n (1 ≤ n ≤ 200 000), the length of a sequence.
The second line contains n integers a1, a2, ..., a**n (|a**i| ≤ 10 000).
Output
Output a real number denoting the minimum possible weakness of a1 - x, a2 - x, ..., a**n - x. Your answer will be considered correct if its relative or absolute error doesn't exceed 10 - 6.
Examples
input
Copy
3
1 2 3
output
Copy
1.000000000000000
input
Copy
4
1 2 3 4
output
Copy
2.000000000000000
input
Copy
10
1 10 2 9 3 8 4 7 5 6
output
Copy
4.500000000000000
Note
For the first case, the optimal value of x is 2 so the sequence becomes - 1, 0, 1 and the max poorness occurs at the segment "-1" or segment "1". The poorness value (answer) equals to 1 in this case.
For the second sample the optimal value of x is 2.5 so the sequence becomes - 1.5, - 0.5, 0.5, 1.5 and the max poorness occurs on segment "-1.5 -0.5" or "0.5 1.5". The poorness value (answer) equals to 2 in this case.
题意:
给你一个长度为\(\mathit n\)的数组\(\mathit a\)
让你寻找一个实数\(\mathit x\),使\(a_1-x,a_2-x,a_3-x,\dots,a_n-x\)的weakness最小。
一个数组的的weakness值是数组所有连续子段的poorness值的最大值。
一个子段的poorness的值是这段子段的数值sum和的绝对值。
思路:
我们定义\(S(i,j)=\sum_{k=i}^j (a_k-x)\)
那么数值\(\mathit a\)的weakness值为:\(max(|S(i,j)|,1\leq i\leq j\leq n\)
而\(|S(i,j)|=max(S(i,j),-1*S(i,j))\)
则:
令:\(A(x)=max(S(i,j),1\leq i\leq j\leq n),B(x)=max(-1*S(i,j),1\leq i\leq j\leq n)\)
则:\(max(|S(i,j)|,1\leq i\leq j\leq n=max(A(x),B(x))\)
显然\(A(x)\)是一个关于\(\mathit x\)的单调递减函数,\(B(x)\)是一个关于\(\mathit x\)的单调递增函数。
那么\(max(A(x),B(x))\)的最小值可以通过二分或者三分来解决:
1️⃣:三分解法:
令\(C(x)=max(A(x),B(x))\),易知\(C(x)\)是一个凹函数,三分凹函数的极小值即可。
2️⃣:二分解法:
令\(C(x)=B(x)-A(x)\),易知\(C(x)\)是一个单调递增的函数,二分出\(C(x)=0\)的点\(x_0\),
答案就是:\(Max(A(x_0),B(x_0))\)
代码:
三分:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#include <sstream>
#include <bitset>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-7
#define chu(x) if(DEBUG_Switch) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
#define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define du2(a,b) scanf("%d %d",&(a),&(b))
#define du1(a) scanf("%d",&(a));
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
ll poww(ll a, ll b) { if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a ;} a = a * a ; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
inline long long readll() {long long tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
inline int readint() {int tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
const int maxn = 1000010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
#define DEBUG_Switch 0
int n;
int a[maxn];
double b[maxn];
double getv(double x)
{
repd(i, 1, n)
{
b[i] = a[i] - x;
}
double res = 0;
double sum = 0;
repd(i, 1, n)
{
sum += b[i];
res = max(res, sum);
if (sum < 0)
sum = 0;
}
sum = 0;
repd(i, 1, n)
{
b[i] *= -1;
}
repd(i, 1, n)
{
sum += b[i];
res = max(res, sum);
if (sum < 0)
sum = 0;
}
return res;
}
int main()
{
#if DEBUG_Switch
freopen("C:\\code\\input.txt", "r", stdin);
#endif
//freopen("C:\\code\\output.txt","r",stdin);
n = readint();
repd(i, 1, n)
{
a[i] = readint();
}
double low = *min_element(a + 1, a + 1 + n);
double high = *max_element(a + 1, a + 1 + n);
repd(rp, 1, 80)
{
double lmid = (low + low + high) / 3.000000;
double rmid = (low + high + high) / 3.000000;
double mv = getv(lmid);
double mmv = getv(rmid);
if (mv > mmv)
{
low = lmid;
} else
{
high = rmid;
}
}
printf("%.6f\n", min(getv(low), getv(high)) );
return 0;
}
二分:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#include <sstream>
#include <bitset>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-7
#define chu(x) if(DEBUG_Switch) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
#define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define du2(a,b) scanf("%d %d",&(a),&(b))
#define du1(a) scanf("%d",&(a));
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
ll poww(ll a, ll b) { if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a ;} a = a * a ; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
inline long long readll() {long long tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
inline int readint() {int tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
const int maxn = 1000010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
#define DEBUG_Switch 0
int n;
int a[maxn];
double b[maxn];
typedef pair<double, double > pdd;
pdd getv(double x)
{
repd(i, 1, n)
{
b[i] = a[i] - x;
}
pdd res = mp(0, 0);
double sum = 0;
repd(i, 1, n)
{
sum += b[i];
res.fi = max(res.fi, sum);
if (sum < 0)
sum = 0;
}
sum = 0;
repd(i, 1, n)
{
b[i] *= -1;
}
repd(i, 1, n)
{
sum += b[i];
res.se = max(res.se, sum);
if (sum < 0)
sum = 0;
}
return res;
}
int main()
{
#if DEBUG_Switch
freopen("C:\\code\\input.txt", "r", stdin);
#endif
//freopen("C:\\code\\output.txt","r",stdin);
n = readint();
repd(i, 1, n)
{
a[i] = readint();
}
double low = *min_element(a + 1, a + 1 + n);
double high = *max_element(a + 1, a + 1 + n);
double ans;
repd(rp, 1, 40)
{
double mid = (low + high) / 2.000000;
pdd res = getv(mid);
if (res.fi > res.se)
{
ans = res.se;
low = mid;
} else
{
high = mid;
}
}
printf("%.6f\n", ans);
return 0;
}