Description
有一个称为“模拟工厂”的游戏是这样的:在时刻0,工厂的生产力等于1。在每个时刻,你可以提高生产力或者生产商品。如果选择提高生产力,在下一个时刻时工厂的生产力加1;如果选择生产商品,则下一个时刻你所拥有的商品数量增加p,其中p是本时刻工厂的生产力。
有n个订单,可以选择接受或者不接受。第i个订单(ti, gi, mi)要求在时刻ti给买家提供gi个商品,事成之后商品数量减少gi,而收入增加mi元。如果接受订单i,则必须恰好在时刻ti交易,不能早也不能晚。同一时刻可以接受多个订单,但每个订单只能被接受一次。要求最后的总收入最大。
例如,如果一共有两个订单(5,1,8)和(7,15,3),用如下策略是最优的:时刻0, 1, 2提高生产力(时刻3的生产力为4),然后在时刻3,4生产商品,则在时刻5时将拥有8个商品。此时接受第1个订单(还会剩下7个商品),并且在时刻5,6继续生产商品,则在时刻7时拥有7+4+4=15个商品,正好满足订单2。
Solution
作为第79和第80个A掉这题的人,感觉很爽啊!!!
蛮诧异这题没什么人A,感觉不太难吧。。
n<=15
爆枚即可,然后check
首先提升生产力想必是在一段区间的开始。
然后对于每个商品,设其开始生产时间为x,就可以列出好多不等式,对于这些不等式,贪心取x最大即可。。
不但卡精度还卡int。。于是改一发全部long long就A了
注:代码有误详情看下面的回复
详细题解戳这里
Code
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<queue>
#include<vector>
#define pb push_back
#define vecn vector<node>
using namespace std;
typedef long long ll;
const ll INF=1ll<<50;
struct node{
ll t,g,m;
inline bool operator < (const node &tmp)const{
return t<tmp.t;
}
}T[20];
ll n,ans=0;
bool mark[20];
vecn G;
inline void Min(ll &a,ll b){
if(a>b)a=b;
}
inline ll Pow(ll x){return 1ll*x*x;}
inline ll Root(ll t,ll g,ll tot){
ll dlt=Pow(t-tot)+4ll*t*tot-4*g;
if(dlt<0)return -1;
return (ll){((double)(t-tot)+(double)sqrt(dlt))/2.0};
}
inline void Max(ll &a,ll b){
if(a<b)a=b;
}
inline void check(ll sum){
G.clear();
for(ll i=1,tot=0;i<=n;++i)
if(mark[i]){
tot+=T[i].g;
G.pb((node){T[i].t,tot});
}
for(ll cas=0,tot=1;cas<G.size();++cas){
ll rtr=INF;
for(ll i=cas;i<G.size();++i){
ll rx=Root(G[i].t,G[i].g,tot);
if((G[i].t-rx)*(rx+tot)<G[i].g)return;
Min(rtr,rx);
}
if(rtr==-1)return;
tot+=rtr;
ll les=1ll*(G[cas].t-rtr)*tot;
for(ll i=cas+1;i<G.size();++i){
G[i].t-=G[cas].t;
G[i].g-=les;
}
}
Max(ans,sum);
}
inline void dfs(ll v=1,ll sum=0){
if(v==n+1)return check(sum);
mark[v]=1;dfs(v+1,sum+T[v].m);
mark[v]=0;dfs(v+1,sum);
}
int main(){
cin>>n;
for(ll i=1;i<=n;++i)
cin>>T[i].t>>T[i].g>>T[i].m;
sort(T+1,T+n+1);
dfs();
cout<<ans<<endl;
return 0;
}