2667: [cqoi2012]模拟工厂
Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 367 Solved: 184
[Submit][Status][Discuss]
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。
Input
输入第一行包含一个整数n,即订单数目。以下n行每行三个整数ti, gi, mi。
Output
输出仅一行,为最大总收入。输出保证在32位带符号整数范围内。
Sample Input
2
5 1 8
7 15 3
5 1 8
7 15 3
Sample Output
11
HINT
编号 |
1-3 |
4-6 |
7-10 |
n |
<=5 |
<=10 |
<=15 |
ti |
100 |
100 |
<=100,000 |
gi |
10,000 |
10,000 |
<=109 |
mi |
10,000 |
10,000 |
<=109 |
Source
考虑贪心,显然每一段先加生产力再生产。
枚举订单后n*n check。
check时我们设当前工作力为g,天数为t,现在剩余a
则得方程(g+x)(t-x)>=a+需求。可解出能够增加生产力的天数。
联立方程,可得若干个区间[l,r]。显然取最小的r作为增加生产力的天数。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #define ll long long 8 using namespace std; 9 ll n; 10 struct data { 11 ll tim,g,m; 12 bool operator <(const data tmp)const { 13 return tim<tmp.tim; 14 } 15 }t[20]; 16 int q[20],tot; 17 ll gets(ll a,ll b,ll c) { 18 ll de=b*b-4*a*c;if(de<0) return -1; 19 double d=sqrt(de); 20 double x1=(-b-d)/(2.0*a),x2=(-b+d)/(2.0*a); 21 return max((ll)floor(x1),(ll)floor(x2)); 22 } 23 ll ans=0; 24 void solve(int x) { 25 ll sum=0;tot=0; 26 for(int i=1;i<=n;i++) if((1<<(i-1))&x) q[++tot]=i; 27 ll s=0,g=1; 28 for(int i=1;i<=tot;i++) { 29 ll tmp=2147483647ll,now=0; 30 for(int j=i;j<=tot;j++) { 31 now+=t[q[j]].g; 32 ll b=t[q[j]].tim-t[q[i-1]].tim; 33 tmp=min(tmp,gets(-1,b-g,b*g+s-now)); 34 if(tmp<0) {sum=0;return;} 35 } 36 g+=tmp;s+=g*(t[q[i]].tim-t[q[i-1]].tim-tmp);sum+=t[q[i]].m;s-=t[q[i]].g; 37 } 38 ans=max(ans,sum); 39 } 40 int main() { 41 scanf("%lld",&n); 42 for(int i=1;i<=n;i++) scanf("%lld%lld%lld",&t[i].tim,&t[i].g,&t[i].m); 43 sort(t+1,t+n+1); 44 for(int i=0;i<=(1<<n)-1;i++) solve(i); 45 printf("%lld",ans); 46 }