CF19B Checkout Assistant
CF19B Checkout Assistant
题目描述
Bob came to a cash & carry store, put nn items into his trolley, and went to the checkout counter to pay. Each item is described by its price c_{i}c**i and time t_{i}t**i in seconds that a checkout assistant spends on this item. While the checkout assistant is occupied with some item, Bob can steal some other items from his trolley. To steal one item Bob needs exactly 1 second. What is the minimum amount of money that Bob will have to pay to the checkout assistant? Remember, please, that it is Bob, who determines the order of items for the checkout assistant.
输入格式
The first input line contains number nn ( 1<=n<=20001<=n<=2000 ). In each of the following nn lines each item is described by a pair of numbers t_{i}t**i , c_{i}c**i ( 0<=t_{i}<=2000,1<=c_{i}<=10^{9}0<=t**i<=2000,1<=c**i<=109 ). If t_{i}t**i is 0, Bob won't be able to steal anything, while the checkout assistant is occupied with item ii .
输出格式
Output one number — answer to the problem: what is the minimum amount of money that Bob will have to pay.
题意翻译
题目描述 Bob 来到一家现购自运商店,将 n 件商品放入了他的手推车,然后到收银台 付款。每件商品由它的价格 pi 和收银员扫描它的时间 ti 秒定义。当收银员正在扫 描某件商品时,Bob 可以从他的手推车中偷走某些其它商品。Bob 需要恰好 1 秒 来偷走一件商品。Bob 需要付给收银员的最少钱数是多少?请记住,收银员扫描 商品的顺序由 Bob 决定。 输入输出格式 输入格式: 输入第一行包含数 n(1≤n≤2000)。接下来 n 行每行每件商品由 一对数 ti,ci(0≤ti≤2000,1≤ci≤10^9)描述。如果 ti 是 0,那么当收银员扫描 商品i时,Bob 不能偷任何东西。 输出格式 输出一个数字——Bob需要支付的最小金额是多少。
题解:
Bob:读书人的事,能叫偷么
看到时间和物品数同级别,给了蒟蒻一丝丝灵感。那么很容易设置一个二维状态,\(dp[i][j]\)表示前i件物品耗时j的最小钱数。蒟蒻一开始以为这样的状态是不合法的,因为蒟蒻以为第二维的枚举范围是\(\sum t_i\)。但是给了你时间你不去偷,还等着结账,那不是纯傻么。
所以对于一个物品来讲,你交了这一份物品的钱,你能拿走的物品数是\(t[i]+1\),也就是结账的时候你尽其所能地偷,最后你还能把这份交了钱的带走。
芜湖?好像像一个背包模型。钱就是价值,体积就是物品数。问题可以转化成至少拿走n个物品的最小价值。为什么是最少而不是恰好呢?因为我们讲对于一份物品的结账过程,最多可以拿\(t[i]+1\),我们为了最优肯定往最多了拿,但是可能到最后一件需要结账的物品时,不用拿这么多就可以了。所以是最少,而不是恰好。并且,通过这个思路,我们可以确定最终答案的统计上限是:\(t_{\max}+n\)。
于是就是普普通通(fcq警告)的背包了。就是这个问题转化让它变成了蓝题。
警告要开longlong,这个家伙让我在11号点见了好多次祖宗。
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
const int maxn=2010;
const int maxm=4010;
const ll INF=9187201950435737471;
int n,maxx;
ll ans=INF;
int t[maxn],c[maxn];
ll dp[maxn][maxm];
//dp[i][j]表示前i件物品耗时j的最小金额
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&t[i],&c[i]);
t[i]++;
maxx=max(maxx,t[i]);
}
maxx+=n;
memset(dp,127,sizeof(dp));
dp[0][0]=0;
for(int i=1;i<=n;i++)
for(int j=0;j<=maxx;j++)
if(j<t[i])
dp[i][j]=dp[i-1][j];
else
dp[i][j]=min(dp[i-1][j],dp[i-1][j-t[i]]+c[i]);
for(int i=n;i<=maxx;i++)
ans=min(ans,dp[n][i]);
printf("%lld",ans);
return 0;
}