CF 808E - Selling Souvenirs 三分

题意:

有N个物品,每个物品有重量(1,2,3)和价值c。

现在问总重量小于等于m的最大价值?

m <= 3e5, n <= 2e5

题解:

背包问题数据加大版,但是重量的种数只有3种。

想DP却无从下手。

其实枚举即可。

枚举重量为3的个数,三分重量为2的个数,就做完了。。

还有一种DP的做法,当然还是枚举3的个数,然后dp[i]代表只用1, 2的重量时最大价值,DP的正确性我不能证明。

代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <bitset>
#include <map>
#include <vector>
#include <stack>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <cmath>
#include <ctime>
#ifdef LOCAL
#define debug(x) cout<<#x<<" = "<<(x)<<endl;
#else
#define debug(x) 1;
#endif

#define chmax(x,y) x=max(x,y)
#define chmin(x,y) x=min(x,y)
#define lson id<<1,l,mid
#define rson id<<1|1,mid+1,r
#define lowbit(x) x&-x
#define mp make_pair
#define pb push_back
#define fir first
#define sec second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, int> pii;

const int MOD = 1e9 + 7;
const double PI = acos (-1.);
const double eps = 1e-10;
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3f;
const int MAXN = 3e5 + 5;

vector<ll> v[4];

ll pre[4][MAXN];

int cmp (int x, int y) {
    return x > y;
}

int n, m;
int n3;
ll calc (int n2) {
    return pre[2][n2] + pre[1][m - 2 * n2 - 3 * n3];
}


ll solve (int l, int r) {
    while (l < r) {
        int m1 = floor (1.0 * (2 * l + r) / 3), m2 = floor (1.0 * (l + 2 * r + 2) / 3);
        if (calc (m1) < calc (m2) ) l = m1 + 1;
        else r = m2 - 1;
    }

    ll vl = calc (l), vr = calc (r);
    return max (vr, vl);
}

int w[MAXN], c[MAXN];

int main() {
#ifdef LOCAL
    freopen ("input.txt", "r", stdin);
#endif
    scanf ("%d %d", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf ("%d %d", &w[i], &c[i]);
        v[w[i]].pb (c[i]);
    }
    for (int i = 1; i <= 3; i++) sort (v[i].begin(), v[i].end(), cmp);
    for (int i = 1; i <= 3; i++) {
        for (int j = 0; j < v[i].size(); j++)
            pre[i][j + 1] = pre[i][j] + v[i][j];
        for (int j = v[i].size(); j < MAXN - 1; j++)
            pre[i][j + 1] = pre[i][j];
    }
    ll ans = 0;
    for (int i = 0; i <= v[3].size(); i++) {
        n3 = i;
        if (i * 3 > m) break;
        ans = max (ans, pre[3][i] + solve (0, (m - 3 * i) / 2) );
    }
    printf ("%lld\n", ans);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/c6376315qqso/article/details/82823851