OVSolitario-io

导航

CF ROUND946 (DIV. 3)E

Money Buys Happiness

题面翻译

你是一个物理学家。一开始你没有钱,每个月的末尾你会得到 \(x\) 英镑。在第 \(i\) 个月里,你可以付出 \(c_i\) 英镑,获取 \(h_i\) 的幸福。

在任何时刻你都不能欠钱,问你在 \(m\) 个月过后最多能获得多少幸福。

保证 \(\sum h_i \leq 10^5\)

题目描述

Being a physicist, Charlie likes to plan his life in simple and precise terms.

For the next $ m $ months, starting with no money, Charlie will work hard and earn $ x $ pounds per month. For the $ i $ -th month $ (1 \le i \le m) $ , there'll be a single opportunity of paying cost $ c_i $ pounds to obtain happiness $ h_i $ .

Borrowing is not allowed. Money earned in the $ i $ -th month can only be spent in a later $ j $ -th month ( $ j>i $ ).

Since physicists don't code, help Charlie find the maximum obtainable sum of happiness.

输入格式

The first line of input contains a single integer $ t $ ( $ 1 \le t \le 1000 $ ) — the number of test cases.

The first line of each test case contains two integers, $ m $ and $ x $ ( $ 1 \le m \le 50 $ , $ 1 \le x \le 10^8 $ ) — the total number of months and the monthly salary.

The $ i $ -th of the following $ m $ lines contains two integers, $ c_i $ and $ h_i $ ( $ 0 \le c_i \le 10^8 $ , $ 1 \le h_i \le 10^3 $ ) — the cost and happiness on offer for the $ i $ -th month. Note that some happiness may be free ( $ c_i=0 $ for some $ i $ 's).

It is guaranteed that the sum of $ \sum_i h_i $ over all test cases does not exceed $ 10^5 $ .

输出格式

For each test case, print a single integer, the maximum sum of happiness Charlie could obtain.

样例 #1

样例输入 #1

7
1 10
1 5
2 80
0 10
200 100
3 100
70 100
100 200
150 150
5 8
3 1
5 3
3 4
1 5
5 3
2 5
1 5
2 1
5 3
2 5
2 4
4 1
5 1
3 4
5 2
2 1
1 2
3 5
3 2
3 2

样例输出 #1

0
10
200
15
1
9
9

提示

In the first test case, Charlie only gets paid at the end of the month, so is unable to afford anything.

In the second test case, Charlie obtains the free happiness in the first month.

In the third test case, it's optimal for Charlie to buy happiness in the second month. Even with money left at the end, Charlie could not go back in time to obtain the happiness on offer in the first month.

本题思路

题目保证在h[i]为1e5,即提示要从h上下文章而不是ci(钱数)

钱数ci很大,且因为m=50无法暴搜(没月选或不选2^m种方案数),要DP

但以当前金钱为状态,每种金钱的最大幸福值,这样dp状态转移数量就会过多
这里反过来设fj表示当前幸福值为j时,当前剩余钱最多是多少

fj表示j这个幸福值剩余钱最多是多少

AC_cdoe

#include <bits/stdc++.h>

using namespace std;
using i64 = long long;
const int inf = 0x3f3f3f3f;
const int N = 2 * 1e5 + 10;

inline int read() {
    int f = 1, x = 0;
    char ch;
    do {
        ch = getchar();
        if(ch == '-') f = -1;
    }while(ch < '0' || ch > '9');
    do {
        x = x * 10 + ch - '0';
        ch = getchar();
    }while(ch >= '0' && ch <= '9');
    return f * x;
}

int a[N], b[N];
i64 f[N];
int _;
int main()
{
    _ = read();
    while(_ -- ) {
        int n, x;
        n = read(), x = read();
        int s = 0;
        for(int i = 1; i <= n; ++ i) {
            a[i] = read(), b[i] = read();
            s += b[i];//计算h
        }
        fill(f, f + s + 1, -1e18);//初始化负无穷
        f[0] = 0;
        //背包:但这里体积和价值调换(每个状态里存价值),即dp值存的是花费
        for(int i = 1; i <= n; ++ i) {
            for(int j = s; j >= 0; -- j) {
                //要买则f[j-b[i]]幸福值状态当前剩余的钱要>=a[i]才可以买,买完之后钱数即f[j-b[i]]-a[i]
                if(j >= b[i] && f[j - b[i]] >= a[i]) f[j] = max(f[j], f[j - b[i]] - a[i]);
                f[j] += x;//每个月加的工资
            }
        }
        int ans = 0;
        for(int i = 1; i <= s; ++ i)//最后看哪个dp数组>=0
            if(f[i] >= 0) ans = i;
        printf("%d\n", ans);
    }
    return 0;
}

本人思路

一眼DP,01背包,设计状态dp[i]:为钱数为i时可以得到的最大价值,倒着做一遍01

因为获得月薪只能第二个月来花,且最后一个月得到的月薪不能花,(处理边界)所以这里从第二个月开始枚举,最后特判一下第一个月是否可以花费 = 0

喜得SF,然后发现dp[i]范围开错,最后输出的应该是超大金钱k···最后还写错甚至没到TLE程度就先WA掉

愚蠢做法

#include <iostream>

using namespace std;
using i64 = long long;

int n, m;
int solve() {
    cin >> n >> m;
    int w[n] {}, h[n] {};
    i64 k = (n - 1) * m + 1;
    i64 dp[k] = {0};
    for(int i = 0; i < n; ++ i) cin >> w[i] >> h[i];
    if(n == 1) {
        if(w[0] == 0) cout << h[1] << endl, 0;
        else return cout << 0 << endl, 0;
    }
    
    for(int i = 1; i < n; ++ i) {
        for(int j = k; j >= w[i]; -- j) {
            dp[j] = max(dp[j], dp[j - w[i]] + h[i]);
        }
    }
    i64 l = 0;
    for(int i = 0; i < k; ++ i) l = max(l, dp[i]);
    if(w[0] == 0) l += h[0];
    
    cout << l << endl;
    return 0;
}

int _;
int main()
{
    cin >> _;
    while(_ -- ) {
        solve();
    }
    return 0;
}

posted on 2024-06-03 21:39  TBeauty  阅读(42)  评论(0)    收藏  举报