LuoguP2115 [USACO14MAR]破坏Sabotage【二分答案】By cellur925

本来是想找一道生成树的题做的...结果被洛咕的标签骗到了这题...结果是二分答案与生成树一点mao关系都没有....



题目大意:给你一个序列,请你删去某一个$l~r$区间的值($2<=i<=j<=n-1$),使得剩余元素的平均值最小。

开始是想二分序列长度的,后来发现没什么卵用。。。于是再想一想二分平均值,但是又感觉并没有二分单调性...(其实是满足的,因为我们二分出的最终答案,当比这个答案大的时候,我们一定能满足,小的时候一定不能满足。)

因为二分的复杂度带了一个$log$,所以我们$check$函数的复杂度必须控制在$O(n)$以内。但是我们要是枚举区间的话即使用上前缀和维护那还是$O(n^2)$的了,显然是不可行的。

我们考虑从最终的式子入手(一个重要的思考方向)

假如我们抹去的区间是$[l,r]$,那么最终的答案就是$(sum[n]-sum[r]+sum[l-1])/(n-(r-l+1))$。因为我们每次二分出来一个期望成为答案的值,只有当所有可能的情况都大于等于我们当前的答案,这个答案才有可能成为真正合法的答案。

再从刚才的答案出发,也就是$(sum[n]-sum[r]+sum[l-1])/(n-(r-l+1))>=x$。然后我们把分母乘过去,进行一顿数学操作,可以得出,最后我们只需要判断任意$(sum[n]-nx)-(sun[j]-jx)+(sum[i-1]-(i-1)x)>=0$是否可行即可。

然后我们会发现式子中有一部分是非常有规律又整齐的。于是我们可以专门搞出一个$p$数组,$p[i]=sum[i]-i*x$($x$为当前二分的答案)。再整理下,最后我们需要判断的就是$p[j]-p[i-1]<=p[n]$。只要有一组$i,j$使$p[j]-p[i-1]>p[n]$,这个答案就报废了==。

于是,我们就考虑用尽量大的来试探。但是又不能枚举区间,所以我们考虑维护两个数组:前缀最小值(因为$j$)和后缀最大值(因为$i$)。这样就好受多了,(感觉这也是个枚举区间的优化技巧啊qwq)

于是我们的$check$函数就写完了。剩下的就只是一些细节方面的赋初值的问题。

Code

 1 #include<cstdio>
 2 #include<algorithm>
 3
 4 using namespace std;
 5 const double eps=1e-8;
 6
 7 int n,v[100090],sum[100090];
 8 double l,r=10090,p[100090],premin[100090],nexmax[100090];
 9
10 bool check(double x)
11 {
12     for(int i=1;i<=n;i++) p[i]=sum[i]-i*x;
13     for(int i=1;i<=n-2;i++) premin[i]=min(p[i],premin[i-1]);
14     for(int i=n-1;i>=2;i--) nexmax[i]=max(nexmax[i+1],p[i]);
15     for(int i=2;i<n;i++)
16         if(nexmax[i]-premin[i-1]>p[n]) return 0;
17     return 1;
18 }
19
20 int main()
21 {
22     scanf("%d",&n);
23     for(int i=1;i<=n;i++) scanf("%d",&v[i]),sum[i]=sum[i-1]+v[i];
24     nexmax[n]=-0x3f3f3f3f,premin[0]=0x3f3f3f3f;
25     while(l+eps<r)
26     {
27         double mid=(l+r)/2;
28         if(check(mid)) l=mid;
29         else r=mid;
30     }
31     printf("%.3lf",l);
32     return 0;
33 }

原文地址:https://www.cnblogs.com/nopartyfoucaodong/p/9784724.html

时间: 2024-10-10 03:39:35

LuoguP2115 [USACO14MAR]破坏Sabotage【二分答案】By cellur925的相关文章

P2115 [USACO14MAR]破坏Sabotage

突然发现好像还没有写二分的题解,那今天就补充一下吧 ----------------------分割线---------------------- 题目描述 Farmer John's arch-nemesis, Farmer Paul, has decided to sabotage Farmer John's milking equipment! The milking equipment consists of a row of N (3 <= N <= 100,000) milking

BZOJ 3477: [Usaco2014 Mar]Sabotage( 二分答案 )

先二分答案m, 然后对于原序列 A[i] = A[i] - m,  然后O(n)找最大连续子序列和, 那么此时序列由 L + mx + R组成. L + mx + R = sum - n * m, sum为原序列的和. 假如二分的答案m是可行的, 那么 L + R = sum - n * m - mx 应该 <= 0 ------------------------------------------------------------------------------------- #inc

洛谷2115 [USACO14MAR]破坏Sabotage

https://www.luogu.org/problem/show?pid=2115 题目描述 Farmer John's arch-nemesis, Farmer Paul, has decided to sabotage Farmer John's milking equipment! The milking equipment consists of a row of N (3 <= N <= 100,000) milking machines, where the ith machi

HDU 5649 DZY Loves Sorting(二分答案+线段树、线段树合并+线段树分割)

题意 一个 \(1\) 到 \(n\) 的全排列,\(m\) 种操作,每次将一段区间 \([l,r]\) 按升序或降序排列,求 \(m\) 次操作后的第 \(k\) 位. \(1 \leq n \leq 10^5\) 思路 两个 \(\log\) 的做法展现了二分答案的强大功能.首先二分枚举第 \(k\) 位的值,然后将小于等于它的数都变为 \(1\) ,大于它的数变为 \(0\) ,线段树可以实现对 \(01\) 序列快速的排序,按要求进行排序,然后如果第 \(k\) 位为 \(1\) 说明这

Codeforces 772A Voltage Keepsake - 二分答案

You have n devices that you want to use simultaneously. The i-th device uses ai units of power per second. This usage is continuous. That is, in λ seconds, the device will use λ·ai units of power. The i-th device currently has bi units of power store

HDU3081Marriage Match II(二分答案+并查集+最大流SAP)经典

Marriage Match II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2507    Accepted Submission(s): 856 Problem Description Presumably, you all have known the question of stable marriage match. A

Codeforce 371C Hamburgers (二分答案)

题目链接 Hamburgers 二分答案,贪心判断即可. 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define REP(i,n) for(int i(0); i < (n); ++i) 6 #define LL long long 7 8 char str[1010]; 9 LL len; 10 LL b, c, s, nb, nc, ns, pb, pc, ps; 11 LL money; 12 13 bool

POJ 3080 Blue Jeans(后缀数组+二分答案)

[题目链接] http://poj.org/problem?id=3080 [题目大意] 求k个串的最长公共子串,如果存在多个则输出字典序最小,如果长度小于3则判断查找失败. [题解] 将所有字符串通过拼接符拼成一个串,做一遍后缀数组,二分答案,对于二分所得值,将h数组大于这个值的相邻元素分为一组,判断组内元素是否覆盖全字典,是则答案成立,对于答案扫描sa,输出第一个扫描到的子串即可. [代码] #include <cstdio> #include <cstring> #inclu

【二分答案+智障的字符串hash】BZOJ2946-[Poi2000]公共串(Ranklist倒一达成!!!!!)【含hash知识点】

[题目大意] 给出几个由小写字母构成的单词,求它们最长的公共子串的长度. [字符串hash的小笔记] hash[i]=(hash[i-1]*p+idx(s[i]))%mod,idx为映射值,一般a..z映射1..26: 习惯上,p取一个6到8位的素数即可,mod一般取大素数 1e9+7(1000000007)或1e9+9(1000000009). hash[i]=(hash[i-1]*p+idx(s[i]))%mod 表示第 i 个前缀的hash值,是一个hash的前缀和,那么,要求S[l…r]