【UVa12563】劲歌金曲

来源:互联网 发布:java程序员月薪 编辑:程序博客网 时间:2024/04/29 08:35

Description

(If you smiled when you see the title, this problem is for you ^_^)
For those who don’t know KTV, see: http://en.wikipedia.org/wiki/Karaoke_box

There is one very popular song called Jin Ge Jin Qu(). It is a mix of 37 songs, and is extremely long (11 minutes and 18 seconds) — I know that there are Jin Ge Jin Qu II and III, and some other.
unofficial versions. But in this problem please forget about them.

Why is it popular? Suppose you have only 15 seconds left (until your time is up), then you should select another song as soon as possible, because the KTV will not crudely stop a song before it ends(people will get frustrated if it does so!). If you select a 2-minute song, you actually get 105 extra seconds! ….and if you select Jin Ge Jin Qu, you’ll get 663 extra seconds!!!

Now that you still have some time, but you’d like to make a plan now. You should stick to the
following rules:

• Don’t sing a song more than once (including Jin Ge Jin Qu).• For each song of length t, either sing it for exactly t seconds, or don’t sing it at all.• When a song is finished, always immediately start a new song. Your goal is simple: sing as many songs as possible, and leave KTV as late as possible (since we have rule 3, this also maximizes the total lengths of all songs we sing) when there are ties.

Translation

(如果你看到这个标题的时候笑了,那么这个问题是为你准备的^ _ ^)

对于那些不知道KTV的人,请看http://en.wikipedia.org/wiki/karaoke_box。

有一首非常流行的歌曲叫做劲歌金曲。它混合了37首歌,是非常长的(11分18秒)-我知道,有劲歌金曲二和三,和其他一些非官方的版本。但在这个问题上,请忽略它们。

为什么它很受欢迎?假设你只剩下15秒的时间,这时你应该尽快选择一首歌,因为KTV不会粗暴地在它结束之前切断一首歌(如果它这样做的话,人们会感到沮丧的!)。如果你选择一个2分钟的歌,你实际上得到额外的105秒!如果你选择了金歌,你会得到额外的663秒!!!

现在你还有一些时间,但你现在想制定一个计划。你应该遵守以下规则:

1.不要重复唱一首歌(包括劲歌金曲)。2.对于每首歌的长度T,要么完整唱T秒,或不唱它。3.当一首歌结束时,总是立即开始一首新歌。

4.你的目标很简单:唱尽可能多的歌曲,让KTV尽可能晚结束(因为我们有规则3,这也最大限度地提高我们唱的所有歌曲的总长度。

Input

The first line contains the number of test cases T (T ≤ 100). Each test case begins with two positive integers n, t (1 ≤ n ≤ 50, 1 ≤ t ≤ 109), the number of candidate songs (BESIDES Jin Ge Jin Qu)
and the time left (in seconds). The next line contains n positive integers, the lengths of each song, in seconds. Each length will be less than 3 minutes — I know that most songs are longer than 3 minutes.

But don’t forget that we could manually “cut” the song after we feel satisfied, before the song ends. So here “length” actually means “length of the part that we want to sing”.

It is guaranteed that the sum of lengths of all songs (including Jin Ge Jin Qu) will be strictly larger than t.

Output

For each test case, print the maximum number of songs (including Jin Ge Jin Qu), and the total lengths of songs that you’ll sing.

Explanation

In the first example, the best we can do is to sing the third song (80 seconds), then Jin Ge Jin Qu for another 678 seconds.

In the second example, we sing the first two (30+69=99 seconds). Then we still have one second left, so we can sing Jin Ge Jin Qu for extra 678 seconds. However, if we sing the first and third song instead (30+70=100 seconds), the time is already up (since we only have 100 seconds in total), so we can’t sing Jin Ge Jin Qu anymore!

SampleInput

2
3 100
60 70 80
3 100
30 69 70

SampleOutput

Case 1: 2 758
Case 2: 3 777

Hint

注意:虽然t<=10^9,但是歌曲的总时长不会超过50*180。后面t再大也是没有用的。

答案要依次满足两个条件:

1.唱的歌尽可能多。2.歌曲的总时长尽可能长。

在限定的条件内选取多个物品,使物品的总价值最大,这不难让我们想到01背包模型。

尝试列出转移式子f[i],表示是正好唱i分钟所唱的最多歌曲数:

f[i]=max(f[i],f[i-time]+1),f[i-time]>=1 or i=time

由于歌曲是一首紧接着一首,所以对于第j首歌,我们只能在正好唱完前一首的情况下转移。

设则最大歌曲数=max(f[i]),为了在满足1的情况下满足2,最大时长=max i,f[i]=最大歌曲数。

最后别忘了加上劲歌金曲。

时间复杂度为O(TnΣtime)。

Code

#include <cstdio>#include <cstring>#include <iostream>using namespace std;const int MAXN=60;const int LIMT=1e4;int T,n,t,tim[60],f[LIMT],p,mx;int getint(){    int v=0; char ch;    while(!isdigit(ch=getchar())); v=ch-48;    while(isdigit(ch=getchar())) v=v*10+ch-48; return v;}int main(){    T=getint();    for(int q=1;q<=T;q++){        n=getint(); t=getint();        mx=0; t--;        memset(f,0,sizeof f);        for(int i=1;i<=n;i++) tim[i]=getint();        for(int i=1;i<=n;i++){            for(int j=t;j>=tim[i];j--){                if(f[j-tim[i]]>=1 || j==tim[i]){                    f[j]=max(f[j],f[j-tim[i]]+1);                    mx=max(mx,f[j]);                }            }        }        for(p=t;f[p]!=mx;p--);        if(mx) printf("Case %d: %d %d\n",q,mx+1,p+678);        else printf("Case %d: %d %d\n",q,1,678);    }    return 0;}
0 0