给个不动脑子的做法。
考虑设 \(f_{i,j,k}\) 为考虑前 \(i\) 个数时,是否存在一种方案,满足两组权值为 \(j,k\)。
考虑转移 \(f_{i,j,k} \to f_{i+1,j,k},f_{i+1,j+x,k},f_{i+1,j,k+x}\),其中 \(x\) 代表第 \(a_i\)。
这样的有效状态是 \(O(n^3t^2)\) 的,单次转移是 \(O(1)\) 的。
01 串,考虑 bitset 优化,优化后复杂度为 \(O(\dfrac{n^3t^2}{w})\)。
这个时候已经可以在给定时间内通过了,但是空间算一下会发现被卡了四倍左右。
滚动数组不太可行,应为要给出方案。
考虑先求出答案,给出方案的时候,分成四个区间 \([1,x_1],[x_1+1,x_2],[x_2+1,x_3],[x_3+1,n]\),每次跑 \([1,x_i]\) 的 dp,但是只保留 \([x_{i-1}+1,x_i]\) 区间的 bitset。
这样分四次统计方案可以减少一个四倍的常数,另外容易被卡时间,稍微写精细点足以通过。
#include <bits/stdc++.h>
#define ll long long
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define pii pair<ll, ll>
#define mp make_pair
#define pb push_back
#define ld lower_bound
#define rep(i, a, b) for (int i = (a); i <= (b); i++)
#define drep(i, a, b) for (int i = (a); i >= (b); i--)
#define ud upper_bound
#define mem(s, k) memset(s, k, sizeof(s))
#define fi first
#define se second
#define ull unsigned long long
#define vec vector <int>
#define fv inline void
#define fn inline static
using u16 = unsigned short; using u32 = unsigned; using u64 = unsigned ll; using u128 = __uint128_t;
using i16 = short; using i32 = ll; using i64 = ll; using i128 = __int128_t;
using namespace std;
const i32 N = 5e2, M = N / 4, V = 4e3;
bitset <V + 5> S[M][V + 5], cl;
i32 n, sum, ans = 1e9, w[N], to[N], op[N], cnt[10];
fn i32 calc(i32 a, i32 b) {return max({a, b, sum - a - b}) - min({a, b, sum - a - b});
}
fv sol(i32 r) {rep (i, 0, M - 1) rep (j, 0, V) S[i][j] = cl;S[to[0] ? to[0] : 0][0] = 1;rep (i, 1, r) {i32 now = (i & 1), lst = (i - 1) & 1;if (to[i]) now = to[i];if (to[i - 1]) lst = to[i - 1];rep (j, 0, V) S[now][j] = cl;rep (j, 0, V) S[now][j] |= S[lst][j];rep (j, w[i], V) S[now][j] |= S[lst][j - w[i]];rep (j, 0, V) S[now][j] |= (S[lst][j] << w[i]);}
}
fn pii find(i32 l, i32 r, i32 a, i32 b, bool opt) {
// cout << l << " " << r << " - " << a << " " << b << "\n"; if (opt) {memset(to, 0, sizeof(to));rep (i, l - 1, r) to[i] = i - l + 3;sol(r);}drep (i, r, l) {if (S[to[i - 1]][a][b]) op[i] = 3, cnt[3]++;else if (b >= w[i] && S[to[i - 1]][a][b - w[i]]) b -= w[i], op[i] = 2, cnt[2]++;else op[i] = 1, cnt[1]++, a -= w[i];}return mp(a, b);
}
int main() {cin >> n;rep (i, 1, n) cin >> w[i], sum += w[i];i32 mid1 = n / 4, mid2 = n / 4 * 2, mid3 = n / 4 * 3;rep (i, mid3, n) to[i] = i - mid3 + 3;sol(n);rep (a, 0, V) {rep (b, 0, V) {if (S[to[n]][a][b]) ans = min(ans, calc(a, b));}}cout << ans << "\n";rep (a, 0, V) {rep (b, 0, V) {if (!S[to[n]][a][b]) continue;if (calc(a, b) == ans) {pii s = find(mid3 + 1, n, a, b, 0);s = find(mid2 + 1, mid3, s.fi, s.se, 1);s = find(mid1 + 1, mid2, s.fi, s.se, 1);find(1, mid1, s.fi, s.se, 1);rep (u, 1, 3) {cout << cnt[u] << " ";rep (i, 1, n) if (op[i] == u) cout << i << " ";cout << "\n";}return 0;}}}
}