結果
| 問題 |
No.2866 yuusaan's Knapsack
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2024-08-30 22:35:09 |
| 言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 692 ms / 2,000 ms |
| コード長 | 2,358 bytes |
| コンパイル時間 | 1,494 ms |
| コンパイル使用メモリ | 125,640 KB |
| 実行使用メモリ | 7,296 KB |
| 最終ジャッジ日時 | 2024-09-26 14:37:16 |
| 合計ジャッジ時間 | 13,018 ms |
|
ジャッジサーバーID (参考情報) |
judge3 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 26 |
ソースコード
#include <iostream>
#include <numeric>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
using ll = long long;
constexpr int iINF = 1'000'000'000;
int main () {
int N, W; cin >> N >> W;
vector<int> v(N), w(N);
for (int i = 0; i < N; i++) cin >> v[i] >> w[i];
// テーブル範囲外に溢れた後にテーブル範囲内に戻ってくる遷移に気を付ければ普通のナップサックになる。
// mapで持って、先にマイナスから処理することにする。
vector<int> index(N);
iota(index.begin(), index.end(), 0);
sort(index.begin(), index.end(), [&] (int a, int b) { return w[a] < w[b]; });
const ll MOD = 998244353;
map<int, int> dp, ndp;
map<int, int> c, nc;
// dp[i] := 重さiで達成できる最大価値
// c[i] := その時点で重さiで達成できる最大価値を作る場合の数
dp[0] = 0;
c[0] = 1;
for (int p = 0; p < N; p++) {
int i = index[p];
ndp.clear();
nc.clear();
for (auto e : dp) {
{ // 取らない
int pre = -iINF;
if (ndp.find(e.first) != ndp.end()) pre = ndp[e.first];
ndp[e.first] = max(pre, e.second);
}
// とる
if (e.first + w[i] <= W) {
int pre = -iINF;
if (ndp.find(e.first + w[i]) != ndp.end()) pre = ndp[e.first + w[i]];
ndp[e.first + w[i]] = max(pre, e.second + v[i]);
}
}
// 場合の数の方の更新
for (auto e : dp) {
// 取らない
if (ndp[e.first] == dp[e.first]) {
nc[e.first] += c[e.first];
nc[e.first] %= MOD;
}
// とる
if (e.first + w[i] <= W) {
if (ndp[e.first + w[i]] == dp[e.first] + v[i]) {
nc[e.first + w[i]] += c[e.first];
nc[e.first + w[i]] %= MOD;
}
}
}
swap(dp, ndp);
swap(c, nc);
}
int max_value = 0;
for (auto e : dp) max_value = max(max_value, e.second);
ll count = 0;
for (auto e : dp) if (max_value == e.second) {
count += c[e.first];
count %= MOD;
}
cout << max_value << " " << count << "\n";
}