「Gym - 100886A」Three Servers

给个不动脑子的做法。

考虑设 \(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;
      }
    }
  }
}
posted @ 2025-03-18 09:18  nullpt3  阅读(124)  评论(0)    收藏  举报