2019.03.12 codeforces739E. Gosha is hunting(dp凸优化)

版权声明:随意转载哦......但还是请注明出处吧: https://blog.csdn.net/dreaming__ldx/article/details/88427230

传送门
题意: n n 个物品,有 a a X X 道具和 b b Y Y 道具, X X 道具移走第 i i 个物品概率为 p i p_i Y Y 道具移走第 i i 个道具概率为 u i u_i
对于每个物品每种道具最多用一次且只能被移走一次,现在问对于道具的所有分配方案中移走物品的总个数的期望最大值是多少。


思路:
有一个很显然的 O ( n 3 ) d p f i , j , k O(n^3)dp:f_{i,j,k} 表示前 i i 个物品用 j j X X 道具和 k k Y Y 道具的最大期望。
然后暴力代码如下:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline int read(){
	int ans=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=getchar();
	return ans;
}
const int N=205;
int n,a,b;
double p[N],u[N],f[N][N][N];
int main(){
	n=read(),a=read(),b=read();
	for(ri i=1;i<=n;++i)scanf("%lf",&p[i]);
	for(ri i=1;i<=n;++i)scanf("%lf",&u[i]);
	for(ri i=1;i<=n;++i){
		for(ri j=0;j<=a;++j)for(ri k=0;k<=b;++k){
			f[i][j][k]=f[i-1][j][k];
			if(j)f[i][j][k]=max(f[i][j][k],f[i-1][j-1][k]+p[i]);
			if(k)f[i][j][k]=max(f[i][j][k],f[i-1][j][k-1]+u[i]);
			if(j&&k)f[i][j][k]=max(f[i][j][k],f[i-1][j-1][k-1]+1-(1-p[i])*(1-u[i]));
		}
	}
	printf("%.6lf",f[n][a][b]);
	return 0;
}

然而这显然是不够优秀的
因此我们发现可以对后两维都进行一次凸优化,复杂度 O ( n l o g n 2 ) O(nlog_n^2)
代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
inline int read(){
	int ans=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=getchar();
	return ans;
}
const double eps=1e-8;
const int N=2005;
int n,a,b;
double p[N],u[N];
struct data{
	double v;
	int a,b;
	data(double v=0,int a=0,int b=0):v(v),a(a),b(b){}
	friend inline data operator+(const data&a,const data&b){return data(a.v+b.v,a.a+b.a,a.b+b.b);}
}f[N];
inline void solve(double w1,double w2){
	f[0]=data(0,0,0);
	for(ri i=1;i<=n;++i){
		f[i]=f[i-1];
		if(f[i-1].v+p[i]-w1>f[i].v)f[i]=f[i-1]+data(p[i]-w1,1,0);
		if(f[i-1].v+u[i]-w2>f[i].v)f[i]=f[i-1]+data(u[i]-w2,0,1);
		if(f[i-1].v+p[i]+u[i]-p[i]*u[i]-w1-w2>f[i].v)f[i]=f[i-1]+data(p[i]+u[i]-p[i]*u[i]-w1-w2,1,1);
	}
}
int main(){
	n=read(),a=read(),b=read();
	for(ri i=1;i<=n;++i)scanf("%lf",&p[i]);
	for(ri i=1;i<=n;++i)scanf("%lf",&u[i]);
	double l1=0,r1=1,l2,r2;
	while(r1-l1>=eps){
		double mid1=(l1+r1)/2;
		l2=0,r2=1;
		while(r2-l2>=eps){
			double mid2=(l2+r2)/2;
			solve(mid1,mid2);
			f[n].b>b?l2=mid2:r2=mid2;
		}
		solve(mid1,r2);
		f[n].a>a?l1=mid1:r1=mid1;
	}
	solve(r1,r2);
	printf("%.6lf",f[n].v+r1*a+r2*b);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/dreaming__ldx/article/details/88427230