Description
如果问一个麦霸:“你在KTV里必唱的曲目有那些?”得到的回答通常包含一首“神曲”――古巨基的《劲歌经典》。为什么呢?一般说来,KTV不会在“时间到”的时候鲁莽地把正在唱的歌切掉,而是会等它放完。例如,在还有15秒时再唱一首2分钟的歌,则实际上多唱了105秒。但是融合了37首歌曲的《劲歌经典》长达11分18秒,如果唱这首歌,相当于多唱了663秒。
假定你正在唱KTV,还剩下t秒时间。你决定下来只唱你最爱的n首歌(不含《劲歌经典》)中的一些,在时间结束之前再唱一个《劲歌金曲》,使得唱的总曲目尽量多(包含《劲歌经典》),在此前提下尽量晚的离开KTV。
Input
第一行为在整数T,表示测试数据组数。 每组测试数据占两行,第一行为整数n和t,分别表示n首歌曲和你还剩下的时间为t秒。第二行为n个整数,分别表示n首的时长(保证不超过3分钟)。 输入保证所有n+1首歌曲的总长度严格大于t。
Output
每组数据输出一行,包含两个整数,分别表示你还能唱的曲目的最多数目和最大的总时长。
01背包问题,只是注意统计答案时不要把f[t]也算进去,因为此时总时间已到,不能唱额外的一首了。
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int MAXN=55;
const int MAXT=9005;
const int ADD=678;
const int INF=200000000;
int T,N,TI,f[MAXT],t[MAXN],sum[MAXN];
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&N,&TI);
int ans=0,num=0;
for(int i=1;i<=N;i++)
{
scanf("%d",&t[i]);
sum[i]=sum[i-1]+t[i];
}
for(int i=1;i<=9000;i++)
f[i]=-INF;
f[0]=0;
for(int i=1;i<=N;i++)
for(int j=min(TI-1,sum[i]);j>=t[i];j--)
f[j]=max(f[j],f[j-t[i]]+1);
for(int i=min(TI-1,sum[N]);i>=0;i--)
{
if(f[i]>num)
{
num=f[i];
ans=i;
}
else if(f[i]==num)
ans=max(ans,i);
}
printf("%d %d",num+1,ans+ADD);
if(T) printf("\n");
}
return 0;
}