BZOJ 2667: [cqoi2012]模拟工厂

16 篇文章 0 订阅
11 篇文章 0 订阅

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;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值