bzoj 2667: [cqoi2012]模拟工厂
由于n≤15,爆枚接受哪些订单
每次Check的时候,对于每段时间显然先提高生产力再生产产品
那么我可以考虑这一段内先尽量提高生产力 但是这样可能会导致生产力提高得太高而没有足够的时间生产产品使得某个订单失败
因此我们计算出对于后面的每一个订单,最多花多少时间提高生产力可以满足如果用接下来的时间都生产的话不至于fail
由于产品数量是关于提高生产力次数的二次函数 因此解个方程就行了
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
#define C (c=getchar ())
#define ll long long
using namespace std;
const ll inf=1ll<<32;
inline void read(int &a)
{
static char c;a=0;C;int f=1;
while (c<'0'||c>'9'){if (c=='-') f=-1;C;}
while (c>='0'&&c<='9') a=(a<<3)+(a<<1)+c-48,C;
a*=f;
}
struct node {
int t,g,m;
}item[17];
inline bool cmp(node a,node b)
{
return a.t<b.t;
}
bool f[17];
int n;
ll ans,tot;
vector<node> q;
inline ll powe(int x){return 1ll*x*x;}
inline ll Root(ll t,ll g,ll tot)
{
ll dlt=powe(t-tot)+4ll*t*tot-4*g;
if(dlt<0)return -1;
return (ll){((double)(t-tot)+(double)sqrt(dlt))/2.0};
}
inline void check(ll sum)
{
register int i,j;
q.clear();tot=0;
for (i=1;i<=n;i++)
if (f[i])
{
tot+=item[i].g;
q.push_back((node){item[i].t,tot});
}
tot=1;
for (i=0;i<q.size();i++)
{
ll r=inf;
for (j=i;j<q.size();j++)
{
ll x=Root(q[j].t,q[j].g,tot);
if ((q[j].t-x)*(x+tot)<q[j].g) return ;
if (x<r) r=x;
}
if (r==-1) return ;
tot+=r;
ll tmp=1ll*(q[i].t-r)*tot;
for (j=i+1;j<q.size();j++)
{
q[j].t-=q[i].t;
q[j].g-=tmp;
}
}
if (sum>ans) ans=sum;
}
void dfs(int now,ll sum)
{
if (now==n+1) {check(sum);return;}
f[now]=1;dfs(now+1,sum+item[now].m);
f[now]=0;dfs(now+1,sum);
}
int main()
{
register int i,j;read(n);
for (i=1;i<=n;i++) read(item[i].t),read(item[i].g),read(item[i].m);
sort(item+1,item+1+n,cmp);
dfs(0,0);
printf("%lld",ans);
}