CQOI2012 模拟工厂

Description

一个工厂每一时刻可以提高 \(1\) 生产力或者生产商品, \(n\) 个订单给出时间,数量,收益,问最大收益。

\(1\leqslant n\leqslant15\)

Solution

首先 \(2^n\) 枚举选哪个订单,然后判断是否可行。

从第一个订单开始,状态可以用剩余存量 \(rem\) 和生产力 \(pro\) 表示,如果当前是第 \(i\) 个订单, \(i-1\)\(i\) 之间时间为 \(t\) ,那么枚举 \(j\)\(i\)\(n\) ,对于 \(i\)\(j\) 这一段都应该是满足总量的,对于 \(j\) ,因为 \(i\sim j-1\) 是已经满足了的,所以我们可以看成这些量都在 \(j\) 的时刻,这样也不会影响对于总量是否合法的判断,这些量总量为 \(sum\) ,若加生产力所需时间为 \(x\) ,那么有 \((t-x)\times (pro+x)+rem\geqslant sum\)\(x^2+x\times(p-t)+s-r-t\times p\leqslant0\),可以解得 \(x\) 的区间为 \([l_j,r_j]\) ,这时总量满足了,但无法判断之后生产的速度能否满足,因此要让 \(pro\) 尽可能大,选最大的 \(\lfloor r_j\rfloor\) 中的最小值即可。

Code

#include<bits/stdc++.h>
using namespace std;
int n;
#define MAXN 20
#define LL long long
#define INF 0x3f3f3f3f3f3f3f3f
struct query
{
	LL t,g,m;
}q[MAXN];
bool cmp(query a,query b){return a.t < b.t;}
bool sel[MAXN];
int s[MAXN],tot; 
long long ans = 0;
LL calc(LL t,LL pro,LL rem,LL sum)//x^2+x*(p-t)+s-r-t*p<=0 
{
	LL a = 1,b = pro - t,c = sum - rem - t * pro;
	LL delta = b * b - 4 * a * c;
	if(delta < 0)return -1;
	return (-b + sqrt((double)delta)) / 2;
}
void solve()
{
	tot = 0;
	for(int i = 1;i <= n;++i)if(sel[i])s[++tot] = i;
	LL pro = 1,rem = 0;
	for(int i = 1;i <= tot;++i)
	{
		LL sum = 0,t = q[s[i]].t - q[s[i - 1]].t;
		LL x = INF;
		for(int j = i;j <= tot;++j)
		{
			sum = sum + q[s[j]].g;
			x = min(x,calc(q[s[j]].t - q[s[i - 1]].t,pro,rem,sum));
		}
		if(x < 0)return;
		pro += x;
		rem = rem + (t - x) * pro - q[s[i]].g;
	}
	LL res = 0;
	for(int i = 1;i <= tot;++i)res += q[s[i]].m;
	ans = max(ans,res);
	return;
}
void dfs(int pos)
{
	if(pos == n + 1){solve();return;}
	sel[pos] = true;dfs(pos + 1);
	sel[pos] = false;dfs(pos + 1);
	return;
}
int main()
{
	scanf("%d",&n);
	for(int i = 1;i <= n;++i)scanf("%lld%lld%lld",&q[i].t,&q[i].g,&q[i].m);
	sort(q + 1,q + 1 + n,cmp);
	dfs(1);
	cout << ans << endl;
	return 0;
}
原文地址:https://www.cnblogs.com/wjh15101051/p/13528580.html