卧薪尝胆,厚积薄发。
CQOI2012 模拟工厂
Date: Wed Aug 19 11:05:18 CST 2020 In Category: NoCategory

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;
}
In tag: 算法-贪心
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡