给定一个长度为n的序列,从中按要求挑选若干个数
- 对于所有的
i
,都必须从a[i],a[i+1]
中至少选一个问取出的数产生的平均数最大是多少?中位数最大是多少?
考虑二分答案,假设二分的答案为
mid
对于平均值,我们可以构造一个数组
b[i]=a[i]-mid
,如果选择出来的数的 ∑ b [ i ] > = 0 \sum{b[i]}>=0 ∑b[i]>=0,就说明平均值大于等于k,所以我们只需要求出满足条件的最大的 ∑ b [ i ] \sum{b[i]} ∑b[i]来作为check
的条件对于中位数,如果选择出来的数中大于等于
mid
的数量大于数量的一半,则中位数大于等于mid
,我们可以构造一个数组b[i] = a[i] >= mid ? 1 : -1
,如果选择出来的数的 ∑ b [ i ] > = 0 \sum{b[i]}>=0 ∑b[i]>=0,就说明中位数大于等于mid
,同意的我们只需要求出满足条件的最大的 ∑ b [ i ] \sum{b[i]} ∑b[i]来作为check
的条件现在的问题转换成给定一个数组
b[i]
,需要满足相邻两项至少选择一项的条件下,最大的和是多少?这就可以考虑
dp
了,dp[i][0]
表示不选择i
能产生的最大的和,dp[i][1]
表示选择i
能产生的最大的和转移方程就很显然了:
d p [ i ] [ 0 ] = d p [ i − 1 ] [ 1 ] ; dp[i][0] = dp[i - 1][1]; dp[i][0]=dp[i−1][1];
d p [ i ] [ 1 ] = m a x ( d p [ i − 1 ] [ 0 ] , d p [ i − 1 ] [ 1 ] ) + b [ i ] ; dp[i][1] = max(dp[i - 1][0], dp[i - 1][1]) + b[i]; dp[i][1]=max(dp[i−1][0],dp[i−1][1])+b[i];
还有需要注意的是二分平均数的时候,
l
和r
等都是double
型的,结束的条件是while(r - l >= 1e-6)
#include
using namespace std;
#define endl '\n'
#define inf 0x3f3f3f3f
#define mod 1000000007
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
typedef long long ll;
typedef pair <int,int> pii;
#define MAX 300000 + 50
int n, m, k;
int tr[MAX];
double dp[MAX][2];
bool check1(double mid){
dp[0][0] = dp[0][1] = 0.0;
for(int i = 1; i <= n; ++i){
dp[i][0] = dp[i - 1][1];
dp[i][1] = max(dp[i - 1][0], dp[i - 1][1]) + tr[i] - mid;
}
if(max(dp[n][1], dp[n][0]) >= 0)return true;
else return false;
}
bool check2(int mid){
dp[0][0] = dp[0][1] = 0;
for(int i = 1; i <= n; ++i){
dp[i][0] = dp[i - 1][1];
dp[i][1] = max(dp[i - 1][0], dp[i - 1][1]) + (tr[i] >= mid ? 1 : -1);
}
if(max(dp[n][1], dp[n][0]) > 0)return true;
else return false;
}
void work(){
cin >> n;
for(int i = 1; i <= n; ++i)cin >> tr[i];
double l = 0, r = 1000000000.0;
while (r - l >= 1e-6) {
double mid = (l + r) / 2;
if(check1(mid))l = mid;
else r = mid;
}
int ll = 0, rr = 1000000000;
while (ll <= rr) {
int mid = (ll + rr) / 2;
if(check2(mid))ll = mid + 1;
else rr = mid - 1;
}
cout << r << '\n' << rr << endl;
}
int main(){
io;
work();
return 0;
}