Gosha is hunting
题解
感觉数据范围好像开太小了,听说出题人当时给出的正解是 O ( n 2 l o g n ) O(n^2log\,n) O(n2logn)的,但我们可以用凸优化做到 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)。
首先我们该如何控制两种球的使用数量分别达到
A
,
B
A,B
A,B呢,显然,dp是一种很容易想到的方法,但
O
(
n
3
)
O(n^3)
O(n3)的时间复杂度明显是过不了的。
考虑我们还有什么方法来控制球使用的数量。
首先,我们想到了凸优化,明显,我们用的球越多期望一定是越大的,所以如果舍掉一维去进行dp的话,他会竟可能多的选择使用这个球。
很明显,我们可以找到一个恰当的值使得每次使用这个球时期望值减去这个值后得到的最优值满足恰好有这么多个球被使用。
而这又是满足单调性的,减去的值越大,球的使用越小。
所以,我们可以去二分
B
B
B球的减去值,找到恰好选择
B
B
B个球的最优解。减去这个值的找最优解方法就是一个很简单的dp。
这样,我们就可以做到
O
(
n
2
l
o
g
n
)
O\left(n^2log\,n\right)
O(n2logn),已经可以过题了。
但很明显,我们可以对
A
A
A球再进行一轮二分,二分一个减去值使得最优解恰好选择
A
A
A个
A
A
A球。
将两个二分套在一起后我们的dp就是一维的了,每次的时间复杂度为
O
(
n
)
O(n)
O(n)。
总时间复杂度为
O
(
n
l
o
g
2
n
)
O\left(nlog^2n\right)
O(nlog2n)。
源码
注意精度!!!
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
using namespace std;
#define MAXN 2005
#define lowbit(x) (x&-x)
#define reg register
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int,int> pii;
const int mo=1e9+7;
const int INF=0x7f7f7f7f;
const double PI=acos(-1.0);
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
int n,A,B;
struct ming{
double val;int cnta,cntb;ming(){val=cnta=cntb=0;}
ming(double V,int Ca,int Cb){val=V;cnta=Ca;cntb=Cb;}
ming operator + (const ming &rhs){return ming(val+rhs.val,cnta+rhs.cnta,cntb+rhs.cntb);}
}dp[MAXN];
ming Max(ming x,ming y){return x.val<y.val?y:x;}
double p[MAXN],u[MAXN],dif1,dif2;
bool check(double k2){
dif2=k2;dp[0]=ming(0,0,0);
for(int i=1;i<=n;i++)
dp[i]=Max(Max(dp[i-1],dp[i-1]+ming(p[i]-dif1,1,0)),Max(dp[i-1]+ming(u[i]-dif2,0,1),dp[i-1]+ming(p[i]+u[i]-p[i]*u[i]-dif1-dif2,1,1)));
return dp[n].cntb>B;
}
bool sakura(double k1){
dif1=k1;double l=0,r=1;int tim1=60;
while(tim1--){
double mid=(l+r)/2.0;
if(check(mid))l=mid;
else r=mid;
}
double mid=(l+r)/2.0;check(r);
return dp[n].cnta>A;
}
signed main(){
read(n);read(A);read(B);
for(int i=1;i<=n;i++)scanf("%lf",&p[i]);
for(int i=1;i<=n;i++)scanf("%lf",&u[i]);
double l=0,r=1;int tim2=50;
while(tim2--){
double mid=(l+r)/2.0;
if(sakura(mid))l=mid;
else r=mid;
}
double mid=(l+r)/2.0;sakura(r);
printf("%.4f\n",dp[n].val+1.0*A*dif1+1.0*B*dif2);
return 0;
}