题意
假定你正在唱KTV,还剩下t秒时间。你决定只唱你最爱的n首歌,并在时间结束之前再唱一首《劲歌金曲》,使得唱的总曲目尽量多,在此前提下尽量晚的离开KTV。
题解
题目中t的范围是1e9但实际的t不会超过10000,这就可以转化为01背包问题。
AC代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
const int maxn = 10000+1;
const int INF = 0x3f3f3f3f;
struct pii{
int cnt, time;
pii(int c = 0, int t = 0):cnt(c),time(t){}
bool operator < (const pii &rhs)const{
return cnt<rhs.cnt || (cnt==rhs.cnt && time<rhs.time);
}
pii operator = (const pii &rhs){
cnt = rhs.cnt;
time = rhs.time;
return *this;
}
};
pii operator + (pii rhs, int t){
rhs.cnt++;
rhs.time += t;
return rhs;
}
int n,m;
pii dp[51][maxn];
int t[maxn];
int main(){
int T, kase = 0;
scanf("%d", &T);
while(T--){
scanf("%d%d", &n, &m);
for(int i = 0; i<n; i++)
scanf("%d", t+i);
for(int i = 1; i<=m; i++){
dp[0][i] = pii(0,0);
if(i > t[0]){
dp[0][i] = pii(1,t[0]);
}
}
for(int i = 1; i<n; i++)
for(int j = 1; j<=m; j++){
dp[i][j] = dp[i-1][j];
if(j > t[i])
dp[i][j] = max(dp[i][j], dp[i-1][j-t[i]] + t[i]);
}
printf("Case %d: ", ++kase);
printf("%d %d\n",dp[n-1][m].cnt+1, dp[n-1][m].time+678);
}
return 0;
}