天天看点

3454. 【NOIP2013中秋节模拟】表白(love)

Love

    • 前言
    • 题目
    • 解法
    • CODE

前言

调了两个小时发现是快排的原因以后就比较崩溃,然后开始看RE的原因。一个double的交换变量我写成了int所以就死循环了。

注意好变量类型,一步步的排除问题要高效一点。不要盲目去排查,不然像这次两小时就没了。

题目

Description

鸡腿是CZYZ的著名DS,但是不想追妹子的DS不是好GFS,所以鸡腿想通过表白来达到他追到妹子的目的!虽然你对鸡腿很无语,但是故事的设定是你帮助鸡腿找到了妹子,所以现在你必须帮助鸡腿安排表白来实现故事的结局 !

鸡腿想到了一个很高(sha)明(bi)的做法,那就是去找人来组成表白队伍来增强气势 !鸡腿有很多好基友来帮忙,鸡腿数了数一共有N个人。但是鸡腿觉得大家排成两队来比较好看,而且鸡腿经过计算,第一队N1个人,第二队N2个人是最佳的队伍。问题来了…有些好基友们虽然很好心但是可能造成不好的影响(形象猥琐),所以鸡腿就给每个人打了分。Q1i表示第i个好基友排到第一队里时的好影响,C1i表示第i个好基友排到第一队里时的不良影响,Q2i表示第i个好基友排到第二队里时的好影响,C2i表示第i个好基友排到第二队里时的不良影响。请给鸡腿一种安排使得Q的和与C的和的比值最大,给出最大值。

Input

第一行给出三个整数N、N1、N2。

第2到N+1行,每行四个整数Q1,C1,Q2,C2。

Output

一行输出一个小数d表示最优化比例是d(保留6位小数)

Sample Input

5 2 2

12 5 8 3

9 4 9 4

7 3 16 6

11 5 7 5

18 10 6 3

Sample Output

2.444444

Data Constraint

对于50%的数据0 < N1 + N2 ≤ N ≤ 50;

对于100%的数据0 < N1 + N2 ≤ N ≤ 500,1 ≤ Q1, Q2 ≤ 2000,1 ≤ C1, C2 ≤ 50。

解法

首先明确01分数规划。

那么我们就可以用到二分答案,所以一个mid要成立,就要成立下列不等式。

由题意得: ∑ x ∈ f i r s t g r o u p ( q 1 i − c 1 i ∗ k ) − ∑ x ∈ s e c o n d g r o u p ( q 2 i − c 2 i ∗ k ) ≥ 0 ∑x∈firstgroup(q1i−c1i∗k)-∑x∈ secondgroup(q2i−c2i∗k)≥0 ∑x∈firstgroup(q1i−c1i∗k)−∑x∈secondgroup(q2i−c2i∗k)≥0

因为是减号,要使得这个值最大,就前面最大,后面最小。

考虑DP

因为要前面的最大,所以其实可以排一下序。从大到小。

设: F i , j F_{i,j} Fi,j​表示从前到i选了j个的最大值。

G i , j G_{i,j} Gi,j​表示从后到i选了j个的最大值。

那么F数组必定是最大的,G数组是最小的。

然后找出最大的f[i][n1]+g[n-i][n2],判断正负即可。

CODE

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#define N 505
#define inf 1000000007
#define ri register int
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
using namespace std;
int n,n1,n2;
int sum=0,kk;
double a[N],q1[N],c1[N],q2[N],c2[N],q3[N],c3[N],q4[N],c4[N],ls;
double f[N][N],g[N][N];
inline int read()
{
	int re=0,ra=1;
	char str=getchar();
	while(str>'9'||str<'0'){str=getchar();if(str=='-') ra=-1;}
	while(str>='0'&&str<='9')re=(re<<1)+(re<<3)+str-'0',str=getchar();
	return re*ra;
}
void qsort(int p,int q)
{
	int i=p,j=q;
	double mi=a[(p+q)/2];
	while(i<=j)
	{
		while(a[i]>mi) i++;while(a[j]<mi) j--;
		if(i<=j) swap(a[i],a[j]),swap(q3[i],q3[j]),swap(c3[i],c3[j]),swap(q4[i],q4[j]),swap(c4[i],c4[j]),i++,j--;
	}if(i<q) qsort(i,q);if(p<j) qsort(p,j);
}
bool check(double t)
{ 
	sum++;
	memset(f,-inf,sizeof(f)),memset(g,-inf,sizeof(g));
	for(ri i=1;i<=n;++i) q3[i]=q1[i],c3[i]=c1[i],q4[i]=q2[i],c4[i]=c2[i];
	for(ri i=1;i<=n;++i) a[i]=(q3[i]-t*c3[i])-(q4[i]-t*c4[i]);
	qsort(1,n);
	f[1][1]=q3[1]-c3[1]*t,f[1][0]=0;
	for(ri i=2;i<=n;++i)
		for(ri j=0;j<=min(i,n1);++j)
			f[i][j]=max(f[i-1][j],f[i-1][j-1]+q3[i]-c3[i]*t);
	g[1][1]=q4[n]-c4[n]*t,g[1][0]=0;
	for(ri i=2;i<=n;++i)
		for(ri j=0;j<=min(i,n2);++j)
			g[i][j]=max(g[i-1][j],g[i-1][j-1]+q4[n-i+1]-c4[n-i+1]*t);
	ls=-1000;
	for(ri i=1;i<=n;++i)	
		if(i>=n1&&n-i>=n2)
			if(f[i][n1]+g[n-i][n2]>ls)
				ls=f[i][n1]+g[n-i][n2];
	if(ls>=0) return true;return false;
}
int main()
{
	fre(love);
	n=read(),n1=read(),n2=read();
	for(ri i=1;i<=n;++i) q1[i]=read(),c1[i]=read(),q2[i]=read(),c2[i]=read();
	double l=0,r=2000.0,mid;
	while(r-l>=0.0000000001)
	{
		mid=(l+r)/2;
		if(check(mid)) l=mid;
		else r=mid;
	}
	printf("%.6lf",mid);
	return 0;
}