結果
問題 | No.2608 Divide into two |
ユーザー | Aeren |
提出日時 | 2024-01-19 21:26:48 |
言語 | C++23 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 14 ms / 1,000 ms |
コード長 | 4,807 bytes |
コンパイル時間 | 3,686 ms |
コンパイル使用メモリ | 278,352 KB |
実行使用メモリ | 5,376 KB |
最終ジャッジ日時 | 2024-09-28 03:57:12 |
合計ジャッジ時間 | 4,349 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge1 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
5,248 KB |
testcase_01 | AC | 5 ms
5,376 KB |
testcase_02 | AC | 14 ms
5,376 KB |
ソースコード
#include <bits/stdc++.h> // #include <x86intrin.h> using namespace std; #if __cplusplus >= 202002L using namespace numbers; #endif // Given a set of items where i-th item has non-negative weight w[i], // find a subset S such that \sum_{i \in S} w[i] <= threshold and \sum_{i \in S} w[i] is maximized struct subset_sum{ vector<int> _pref; vector<vector<int>> _dp; vector<vector<array<int, 2>>> _prev; // w[i] < weight_bound // O(n * bound) void run_for_bounded_weight(const vector<int> &w, int weight_bound, int threshold){ assert(weight_bound > 0 && threshold >= 0); for(auto x: w) assert(0 <= x && x < weight_bound); int n = (int)w.size(); _pref = {0}; while((int)_pref.size() - 1 < n && _pref.back() + w[(int)_pref.size() - 1] <= threshold) _pref.push_back(_pref.back() + w[(int)_pref.size() - 1]); const int cut = (int)_pref.size() - 1; if(n == cut){ subset_weight = _pref[n]; in_subset.assign(n, true); subset.resize(n); iota(subset.begin(), subset.end(), 0); return; } _dp.assign(n - cut + 1, vector<int>(weight_bound << 1)); _prev.assign(n - cut + 1, vector<array<int, 2>>(weight_bound << 1, {-1, -1})); fill(_dp[0].begin() + weight_bound, _dp[0].end(), 0); _dp[0][weight_bound - 1] = cut + 1; for(auto x = weight_bound - 1; x >= 0; -- x) if(_dp[0][x]) for(auto l = _dp[0][x] - 1; l >= 1; -- l){ if(x >= w[l - 1] && _dp[0][x - w[l - 1]] < l){ _dp[0][x - w[l - 1]] = l; _prev[0][x - w[l - 1]] = {0, x}; } } for(auto r = 1; r <= n - cut; ++ r) for(auto x = 2 * weight_bound - 1; x >= 0; -- x){ if(_dp[r][x] < _dp[r - 1][x]){ _dp[r][x] = _dp[r - 1][x]; _prev[r][x] = {r - 1, x}; } if(x >= w[cut + r - 1] && _dp[r][x] < _dp[r - 1][x - w[cut + r - 1]]){ _dp[r][x] = _dp[r - 1][x - w[cut + r - 1]]; _prev[r][x] = {r - 1, x - w[cut + r - 1]}; } for(auto l = _dp[r][x] - 1; l >= max(1, _dp[r - 1][x]); -- l) if(x >= w[l - 1] && _dp[r][x - w[l - 1]] < l){ _dp[r][x - w[l - 1]] = l; _prev[r][x - w[l - 1]] = {r, x}; } } subset_weight = threshold; while(!_dp[n - cut][subset_weight - _pref.back() + weight_bound - 1]) -- subset_weight; in_subset.assign(n, false); fill(in_subset.begin(), in_subset.begin() + cut, true); for(auto r = n - cut, weight = subset_weight - _pref.back() + weight_bound - 1; ; ){ auto [nr, nweight] = _prev[r][weight]; if(!~nr) break; if(r == nr) in_subset[_dp[r][weight] - 1] = false; else if(weight != nweight) in_subset[cut + r - 1] = true; r = nr, weight = nweight; } subset.clear(); for(auto i = 0; i < n; ++ i) if(in_subset[i]) subset.push_back(i); } // O(n * log(\sum{w}) + SZ * sqrt(\sum{w}) / bit_width) template<size_t SZ> void run_for_small_total_weight(const vector<int> &w, int threshold){ assert(threshold >= 0 && threshold < SZ); int n = (int)w.size(); map<int, list<list<int>>> mp; for(auto i = 0; i < (int)w.size(); ++ i) mp[w[i]].push_back({i}); vector<pair<int, list<int>>> ordered_pool; while(!mp.empty()){ int weight = mp.begin()->first; auto &from = mp.begin()->second; if((int)from.size() >= 3){ auto &to = mp[weight << 1]; while((int)from.size() >= 3){ next(from.begin())->splice(next(from.begin())->begin(), from.front()); from.pop_front(); to.push_back(move(from.front())); from.pop_front(); } } for(; !from.empty(); from.pop_front()) ordered_pool.push_back({weight, move(from.front())}); mp.erase(mp.begin()); } vector<int> first_appear(threshold + 1, -1); bitset<SZ> dp{}; dp[0] = true; for(auto i = 0; i < (int)ordered_pool.size(); ++ i){ int weight = ordered_pool[i].first; auto dp_next = dp | dp << weight; auto dif = dp ^ dp_next; for(auto x = dif._Find_first(); x <= threshold; x = dif._Find_next(x)) first_appear[x] = i; dp = dp_next; } subset_weight = threshold; while(!dp[subset_weight]) -- subset_weight; in_subset.assign(n, false); subset.clear(); for(auto weight = subset_weight; weight; ){ int i = first_appear[weight]; for(auto ind: ordered_pool[i].second){ in_subset[ind] = true; subset.push_back(ind); } weight -= ordered_pool[i].first; } } int subset_weight; vector<int> in_subset, subset; }; int main(){ cin.tie(0)->sync_with_stdio(0); cin.exceptions(ios::badbit | ios::failbit); auto __solve_tc = [&](auto __tc_num)->int{ int n; cin >> n; if(n * (n + 1) / 2 & 1){ cout << "-1\n"; return 0; } subset_sum ss; vector<int> a(n); iota(a.begin(), a.end(), 1); ss.run_for_small_total_weight<10001>(a, n * (n + 1) / 4); ranges::copy(ss.in_subset, ostream_iterator<int>(cout, "")); cout << "\n"; return 0; }; int __tc_cnt; cin >> __tc_cnt; for(auto __tc_num = 0; __tc_num < __tc_cnt; ++ __tc_num){ __solve_tc(__tc_num); } return 0; } /* */