結果
| 問題 |
No.2608 Divide into two
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2024-01-19 21:26:48 |
| 言語 | C++23 (gcc 13.3.0 + boost 1.87.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 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 1 |
| other | AC * 2 |
ソースコード
#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;
}
/*
*/