CF739E Gosha is hunting(wqs 二分)

· · 题解

首先有一个 O(n^2\log n) 的做法,就是二分斜率 k,然后每用一个 A 类球答案就减 k,dp 求出 B 类球取 b 个的答案。正确性和实现可以参考其他题解。

考虑每个位置的四种选择:

  1. 用 A 和 B,答案加 p+u-pu-k

  2. 用 B,答案加 u-k

  3. 用 A,答案加 p

  4. 都不用,答案加 0

考虑一个位置从不用 B 变成用 B,答案的增加量就是 x=\max(p+u-pu-k,p)-\max(u-k,0),对 x 从大到小排序,取前 b 个即可。

可以分四种情况归并省掉排序,优化到 O(n\log n)

```cpp #include<bits/stdc++.h> using namespace std; enum{N=2009}; double ans,p[N],u[N]; int n,a,b; struct T{ double x; int a0,a1; }t[N]; bool chk(double k){ int i,c=0; ans=0; for(i=1;i<=n;++i){ if(p[i]>p[i]+u[i]-p[i]*u[i]-k)t[i].a1=0,t[i].x=p[i]; else t[i].a1=1,t[i].x=p[i]+u[i]-p[i]*u[i]-k; if(0>u[i]-k)t[i].a0=0; else t[i].a0=1,t[i].x-=u[i]-k,ans+=u[i]-k; } sort(t+1,t+n+1,[](T a,T b){return a.x>b.x;}); for(i=1;i<=a;++i)c+=t[i].a1,ans+=t[i].x; for(;i<=n;++i)c+=t[i].a0; return c<b; } int main(){ios::sync_with_stdio(0);cin.tie(0); double l=0,r=1,m; int i; cin>>n>>a>>b; for(i=1;i<=n;++i)cin>>p[i]; for(i=1;i<=n;++i)cin>>u[i]; for(i=1;i<77;++i){ m=(l+r)/2; if(chk(m))r=m;else l=m; } cout<<fixed<<setprecision(9)<<ans+b*m; } ``` 暂时能过讨论区所有 hack 数据。