Google Kickstart 能量石

题目描述
岩石怪物杜达生活在魔法森林中,他在午餐时收集了 $N$ 块能量石准备开吃。

由于他的嘴很小,所以一次只能吃一块能量石。

能量石很硬,吃完需要花不少时间。

吃完第 $i$ 块能量石需要花费的时间为 $S_i$ 秒。

杜达靠吃能量石来获取能量。

不同的能量石包含的能量可能不同。

此外,能量石会随着时间流逝逐渐失去能量。

第 $i$ 块能量石最初包含 $E_i$ 单位的能量,并且每秒将失去 $L_i$ 单位的能量。

当杜达开始吃一块能量石时,他就会立即获得该能量石所含的全部能量(无论实际吃完该石头需要多少时间)。

能量石中包含的能量最多降低至 $0$。

请问杜达通过吃能量石可以获得的最大能量是多少?

输入格式
第一行包含整数 $T$,表示共有 $T$ 组测试数据。

每组数据第一行包含整数 $N$,表示能量石的数量。

接下来 $N$ 行,每行包含三个整数 $S_i$,$E_i$,$L_i$。

输出格式
每组数据输出一个结果,每个结果占一行。

结果表示为 Case #x: y,其中 $x$ 是组别编号(从 $1$ 开始),$y$ 是可以获得的最大能量值。

数据范围
$1≤T≤10$,
$1≤N≤100$,
$1≤Si≤100$,
$1≤Ei≤105$,
$0≤Li≤105$

输入样例:

3
4
20 10 1
5 30 5
100 30 1
5 80 60
3
10 4 1000
10 3 1000
10 8 1000
2
12 300 50
5 200 0

输出样例:

Case #1: 105
Case #2: 8
Case #3: 500

我们直接开门见山

这里我先列举两个理解点:

  1. 不能直接枚举吃不吃每个石头,因为最终的收益还与吃的时机有关,不仅仅与吃不吃有关,假如一个能量石吃要很久,但是衰减的很慢,另一个能量石吃很快,衰减的很快,如果先考虑第一个能量石,即便吃了第二个能量石也变为0了,而如果不吃,又少了第一个能量石的能量,所以如果先吃2再吃1就两者皆可得
  2. 状态转移方程中,$e-(j-s)l<0$ 的理解:令 $t=e-(j-s)l<0$,如果 $dp[j-s]+t>dp[j]$,可以被能量值为0或负数的能量石更新。那么必然有 $dp[j-s]>=dp[j]$,这就存在一种情况是时间长的吃得所获得得能量还少,那么最终的最优解必然不会从这一轮的 $dp[j]$ 更新过来,因为这一轮的 $dp[j-s]$ 等于上一轮的 $dp[j-s]$ ,其值更大,时间更短。(注意一维方式是从大到小枚举时间 $j$ )

如何排序:

假设考虑第 $i$ 和第 $i+1$ 个能量石

先吃 $i$ 的可获得的能量:$$E_i+E_{i+1}-S_i*L_{i+1}$$.

先吃 $i+1$ 可获得的能量:$$E_i+E_{i+1}-S_{i+1}*L_i$$.

那么如果 $S_i*L_{i+1}<S_{i+1}L_i$ 即可获得的能量较大,如果不是,则先吃 $i+1$,

那么我们就可以根据这个排序了!

接下来就是01背包了

C++代码

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int N=110,M=100010;

struct Stone
{
    int e,s,l;
    bool operator < (const Stone &oo) const
    {
        return s*oo.l<oo.s*l;
    }
}stone[N];

int n,dp[M];

int main()
{
    int T; cin>>T;
    for(int k=1;k<=T;k++)
    {
        cin>>n;
        int m=0;
        for(int i=0;i<n;i++) 
        {
            cin>>stone[i].s>>stone[i].e>>stone[i].l;
            m+=stone[i].s;
        }

        sort(stone,stone+n);

        memset(dp,-0x3f,sizeof dp);
        dp[0]=0;
        for(int i=0;i<n;i++)
        {
            int s=stone[i].s,l=stone[i].l,e=stone[i].e;
            for(int j=m;j>=s;j--)
                if(e-(j-s)*l>0) //这一步可以没有,但是亲测加上快了100ms
                    dp[j]=max(dp[j],dp[j-s]+e-(j-s)*l);
        }

        int res=0;
        for(int i=0;i<=m;i++) res=max(res,dp[i]);

        printf("Case #%d: %d\n",k,res);
    }
    return 0;
}

评论

  1. ToT
    3 年前
    2022-12-14 13:53:35

    test

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇