其他分享
首页 > 其他分享> > [2021 ICPC 昆明 G] Gift

[2021 ICPC 昆明 G] Gift

作者:互联网

https://ac.nowcoder.com/acm/contest/12548/G

题意:
假设现在是\(2021\)年的第一天。你有\(n\)个朋友,\(m\)个可购买的礼物,以及\(w\)元。给出每个朋友的生日、你亲手为他们制作礼物的时间以及你亲手制作礼物能得到的好感度。你每天只能进行一种礼物的制作,但可以不连续制作同一个礼物。当然,你也可以选择直接购买礼物,花费\(a_i\)元,对于每个朋友,都能获得\(b_i\)好感度。每个人都只能在生日当天收一次礼物,问你今年能收获的最大好感度是多少。

思路:
想不到好的贪心,题面也有点像背包,那么考虑\(dp\)。考虑他给出的各项参数,发现\(O(365 * N * M * T)\)差不多正好能符合\(1s\)的时限。生日是有先有后的,我们要符合递推的顺序。所以我们记录下每个人生日距离\(1\)月\(1\)日的天数,以天数为关键字进行升序排序,同时第一维也可以降下来。\(dp[i][j]\)代表花费i天制作礼物,买了\(j\)个礼物后,能获得的最大好感度。写的时候发现买礼物时,并不好决定当下买哪个礼物,那么我们预处理一下,用状压处理出买对应数量礼物时,能获得的最大好感度,在最后找答案的时候加上去就行了。注意背包的两维要从后往前,避免重复送礼物。最后还要注意\(2\)月\(29\)的情况,因为\(2021\)年不是闰年,要直接不管这一天。一直想知道这天过生日的是4年过一次吗(逃

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int N = 5e2 + 7;

struct Fir{
    int d, c, v;

    Fir () {}
    Fir (int d, int c, int v) : d(d), c(c), v(v) {}

    bool operator < (const Fir & f) const {
        return d < f.d;
    }
}fir[N];

int n, m, w;
int a[17], b[17];
int dp[371][17];
int add[17];
int pre[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

void solve() {
    memset(dp, -0x3f, sizeof(dp));
    memset(add, 0, sizeof(add));
    scanf("%d %d %d", &n, &m, &w);
    int tot = 0;
    for (int i = 1; i <= n; ++i) {
        int yy, mm, dd, cc, vv;
        scanf("%d-%d-%d %d %d", &yy, &mm, &dd, &cc, &vv);
        if (mm == 2 && dd == 29) continue;
        tot++;
        fir[tot] = Fir(pre[mm - 1] + dd, cc, vv);
    }
    sort(fir + 1, fir + 1 + tot);
    for (int i = 1; i <= m; ++i) {
        scanf("%d %d", &a[i], &b[i]);
    }
    int ed = 1 << m;
    for (int i = 1; i < ed; ++i) {
        int cost = 0;
        int val = 0;
        int num = 0;
        int sta = i;
        for (int j = 1; j <= m; ++j) {
            if (sta & 1) cost += a[j], val += b[j], num++;
            sta >>= 1;
        }
        if (cost <= w) add[num] = max(add[num], val);
    }
    dp[0][0] = 0;
    for (int i = 1; i <= tot; ++i) {
        for (int j = 365; j >= 0; --j) {
            for (int k = m; k >= 0; --k) {
                if (k + 1 <= m) dp[j][k + 1] = max(dp[j][k + 1], dp[j][k]);
                if (j + fir[i].c <= 365 && j + fir[i].c <= fir[i].d) { // 这里注意判断下之前的天数够不够,不够的话是不能赶在生日当天送礼物的
                    dp[j + fir[i].c][k] = max(dp[j + fir[i].c][k], dp[j][k] + fir[i].v);
                }
            }
        }
    }
    int ans = -inf;
    for (int i = 1; i <= 365; ++i) {
        for (int j = 0; j <= m; ++j) {
            ans = max(ans, dp[i][j] + add[j]);
        }
    }
    printf("%d\n", ans);
}

int main() {
    for (int i = 1; i <= 12; ++i) pre[i] += pre[i - 1];
    int t = 1;
    scanf("%d", &t);
    while (t--) solve();
    return 0;
}

标签:const,Gift,int,31,ICPC,2021,好感度,dp,礼物
来源: https://www.cnblogs.com/Sstee1XD/p/14675777.html