十连测 D2T2 market(二分+背包)

在比特镇一共有 n 家商店,编号依次为 1 到 n。每家商店只会卖一种物品,其中第 i 家商店的物品
单价为 ci,价值为 vi,且该商店开张的时间为 ti。
Byteasar 计划进行 m 次购物,其中第 i 次购物的时间为 Ti,预算为 Mi。每次购物的时候, Byteasar
会在每家商店购买最多一件物品,当然他也可以选择什么都不买。如果购物的时间早于商店开张的时间,
那么显然他无法在这家商店进行购物。
现在 Byteasar 想知道,对于每个计划,他最多能购入总价值多少的物品。请写一个程序,帮助
Byteasar 合理安排购物计划。
注意:每次所花金额不得超过预算,预算也不一定要花完,同时预算不能留给其它计划使用。
Input
第一行包含两个正整数 n; m,表示商店的总数和计划购物的次数。
接下来 n 行,每行三个正整数 ci; vi; ti,分别表示每家商店的单价、价值以及开张时间。
接下来 m 行,每行两个正整数 Ti; Mi,分别表示每个购物计划的时间和预算。
Output
输出 m 行,每行一个整数,对于每个计划输出最大可能的价值和。
Examples
market.in
5 2
5 5 4
1 3 1
3 4 3
6 2 2
4 3 2
3 8
5 9
market.out
10
12
第一个计划可以在商店 2,3,5 各购买一件物品,总花费为 1 + 3 + 4 = 8,总价值为 3 + 4 + 3 = 10。
第二个计划可以在商店 1,2,3 各购买一件物品,总花费为 5 + 1 + 3 = 9,总价值为 5 + 3 + 4 = 12。

Day 2
Notes
对于 100% 的数据, 1 ≤ ti;Ti ≤ n。

这里写图片描述

这里写代码片
program df;
var i,j,n,m,x,y,z,k,t,l,r,mid,sum:longint;
a,b,c:array[0..300] of longint;
f:array[-1..300,-1..90000] of longint;
procedure sq(l,r:longint);
var i,j,mm,dd:longint;
begin
i:=l; j:=r;
mm:=c[(l+r) div 2];
repeat
while c[i]<mm do inc(i);
while c[j]>mm do dec(j);
if i<=j then
begin
dd:=a[i]; a[i]:=a[j]; a[j]:=dd;
dd:=b[i]; b[i]:=b[j]; b[j]:=dd;
dd:=c[i]; c[i]:=c[j]; c[j]:=dd;
inc(i); dec(j);
end;
until i>j;
if l<j then sq(l,j);
if i<r then sq(i,r);
end;

function check(x:longint):longint;
var l,r,mid:longint;
begin
l:=0; r:=n;
while l<r-1 do
begin
mid:=(l+r) div 2;
if c[mid]<=x then l:=mid
else r:=mid;
end;
if c[r]<=x then
exit(r)
else exit(l);
end;


function min(x,y:longint):longint;
begin
if x>y then exit(y)
else exit(x);
end;

function deal(x,y:longint):longint;
var l,r,mid:longint;
begin
l:=0; r:=sum;
while l<r-1 do
begin
mid:=(l+r) div 2;
if f[x,mid]<=y then l:=mid
else r:=mid;
end;
if f[x,r]<=y then exit(r)
else exit(l);
end;


begin
assign(input,'market.in');
reset(input);
assign(output,'market.out');
rewrite(output);



readln(n,k);
for i:=1 to n do
begin
readln(a[i],b[i],c[i]);
sum:=sum+b[i];
end;

sq(1,n);


for i:=0 to n do
for j:=1 to sum do
f[i,j]:=maxlongint div 2-10;


for i:=1 to n do
for j:=1 to sum do //f[i,j]为当前i个商店,价值为j的最小预算为多少
begin
if (j<b[i]) then f[i,j]:=f[i-1,j]
else f[i,j]:=min(f[i-1,j],f[i-1,j-b[i]]+a[i]);
end;     //背包不解释

for i:=1 to n do
for j:=sum-1 downto 0 do
f[i,j]:=min(f[i,j],f[i,j+1]);   // 使答案具有单调性,能够二分(让答案前面的值都等于答案,答案后面的值都大于答案)

for i:=1 to k do
begin
readln(t,m);
x:=check(t);
if x=0 then writeln(0)
else
writeln(deal(x,m));
end;
close(input);
close(output);
end.
posted @ 2017-09-10 09:10  Gxyhqzt  阅读(185)  评论(0编辑  收藏  举报