QOJ.ac

QOJ

IDSubmission IDProblemHackerOwnerResultSubmit timeJudge time
#507#305128#8005. Crossing the Borderhos_lyrichos_lyricFailed.2024-01-14 18:50:482024-01-14 18:50:50

Details

Extra Test:

Accepted
time: 4309ms
memory: 493944kb

input:

22 6016
3009 40000001
3008 40000002
3007 40000004
3006 40000008
3005 40000016
3004 40000032
2010 40000064
2009 40000128
2008 40000256
2007 40000512
2006 40001024
2005 40002048
2004 40004096
2003 40008192
2002 40016384
1006 40032768
1005 40065536
1004 40131072
1003 40262144
1002 40524288
1001 4104857...

output:

322134700 2

result:

ok 2 number(s): "322134700 2"

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#305128#8005. Crossing the Borderhos_lyricAC ✓3373ms494784kbC++144.6kb2024-01-14 18:48:592024-01-14 18:48:59

answer

#include <cassert>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <functional>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

using namespace std;

using Int = long long;

template <class T1, class T2> ostream &operator<<(ostream &os, const pair<T1, T2> &a) { return os << "(" << a.first << ", " << a.second << ")"; };
template <class T> ostream &operator<<(ostream &os, const vector<T> &as) { const int sz = as.size(); os << "["; for (int i = 0; i < sz; ++i) { if (i >= 256) { os << ", ..."; break; } if (i > 0) { os << ", "; } os << as[i]; } return os << "]"; }
template <class T> void pv(T a, T b) { for (T i = a; i != b; ++i) cerr << *i << " "; cerr << endl; }
template <class T> bool chmin(T &t, const T &f) { if (t > f) { t = f; return true; } return false; }
template <class T> bool chmax(T &t, const T &f) { if (t < f) { t = f; return true; } return false; }
#define COLOR(s) ("\x1b[" s "m")


// as * bs
// ZT: T[2^n][n+1]
template <class T, class ZT>
vector<T> setMul(int n, const vector<T> &as, const vector<T> &bs, ZT zas, ZT zbs) {
  assert(static_cast<int>(as.size()) == 1 << n);
  assert(static_cast<int>(bs.size()) == 1 << n);
  // ranked
  for (int h = 0; h < 1 << n; ++h) {
    memset(zas[h], 0, (n + 1) * sizeof(T));
    zas[h][__builtin_popcount(h)] = as[h];
  }
  for (int h = 0; h < 1 << n; ++h) {
    memset(zbs[h], 0, (n + 1) * sizeof(T));
    zbs[h][__builtin_popcount(h)] = bs[h];
  }
  // zeta
  for (int w = 1; w < 1 << n; w <<= 1) {
    for (int h0 = 0; h0 < 1 << n; h0 += w << 1) for (int h = h0; h < h0 + w; ++h) {
      for (int k = 0; k <= n; ++k) zas[h + w][k] += zas[h][k];
    }
  }
  for (int w = 1; w < 1 << n; w <<= 1) {
    for (int h0 = 0; h0 < 1 << n; h0 += w << 1) for (int h = h0; h < h0 + w; ++h) {
      for (int k = 0; k <= n; ++k) zbs[h + w][k] += zbs[h][k];
    }
  }
  // product
  for (int h = 0; h < 1 << n; ++h) {
    for (int k = n; k >= 0; --k) {
      T t = 0;
      for (int l = 0; l <= k; ++l) t += zas[h][l] * zbs[h][k - l];
      zas[h][k] = t;
    }
  }
  // moebius
  for (int w = 1; w < 1 << n; w <<= 1) {
    for (int h0 = 0; h0 < 1 << n; h0 += w << 1) for (int h = h0; h < h0 + w; ++h) {
      for (int k = 0; k <= n; ++k) zas[h + w][k] -= zas[h][k];
    }
  }
  // unrank
  vector<T> cs(1 << n);
  for (int h = 0; h < 1 << n; ++h) cs[h] = zas[h][__builtin_popcount(h)];
  return cs;
}


constexpr int MO = 998244353;
constexpr int MAX_N = 22;
constexpr int INF = 1001001001;

Int zas[1 << MAX_N][MAX_N + 1];
Int zbs[1 << MAX_N][MAX_N + 1];

int N, W;
vector<pair<int, int>> P;

int main() {
  for (; ~scanf("%d%d", &N, &W); ) {
    P.resize(N);
    for (int i = 0; i < N; ++i) {
      scanf("%d%d", &P[i].second, &P[i].first);
    }
    sort(P.begin(), P.end());
    
    vector<int> sums(1 << N, 0);
    for (int i = 0; i < N; ++i) {
      for (int h = 0; h < 1 << i; ++h) {
        sums[h | 1 << i] = sums[h] + P[i].second;
      }
    }
    
    // dp[h]: used h
    vector<pair<int, Int>> dp(1 << N, make_pair(INF, 0));
    for (int h = 1 << (N - 1); h < 1 << N; ++h) if (sums[h] <= W) {
      dp[h] = make_pair(P[N - 1].first, 1);
    }
    for (int i = N - 1; --i >= 0; ) {
      auto crt = dp.end() - (1 << (i + 1));
      auto nxt = dp.end() - (1 << i);
      vector<int> vals(1 << i);
      for (int h = 0; h < 1 << i; ++h) vals[h] = crt[h].first;
      sort(vals.begin(), vals.end());
      vals.erase(unique(vals.begin(), vals.end()), vals.end());
cerr<<i<<": "<<vals.size()<<endl;
      vector<Int> fs(1 << i, 0);
      for (int h = 0; h < 1 << i; ++h) if (sums[h | 1 << i] <= W) fs[h] = 1;
      for (const int val : vals) if (val < INF) {
        const int cost = P[i].first + val;
        vector<Int> gs(1 << i, 0);
        for (int h = 0; h < 1 << i; ++h) if (crt[h].first == val) gs[h] = crt[h].second;
        const auto prod = setMul(i, fs, gs, zas, zbs);
        for (int h = 0; h < 1 << i; ++h) if (prod[h]) {
          if (nxt[h].first > cost) {
            nxt[h].first = cost;
            nxt[h].second = prod[h];
          } else if (nxt[h].first == cost) {
            nxt[h].second += prod[h];
          }
        }
      }
    }
    printf("%d %lld\n", dp.back().first, dp.back().second % MO);
  }
  return 0;
}