QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#290470#4820. Kitten's Computerucup-team087#AC ✓3ms4068kbC++147.7kb2023-12-25 01:54:212023-12-25 01:54:21

Judging History

你现在查看的是最新测评结果

  • [2023-12-25 01:54:21]
  • 评测
  • 测评结果:AC
  • 用时:3ms
  • 内存:4068kb
  • [2023-12-25 01:54:21]
  • 提交

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 <map>
#include <numeric>
#include <queue>
#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; }

unsigned xrand() {
  static unsigned x = 314159265, y = 358979323, z = 846264338, w = 327950288;
  unsigned t = x ^ x << 11; x = y; y = z; z = w; return w = w ^ w >> 19 ^ t ^ t >> 8;
}
unsigned long long gen() {
  unsigned long long ret = xrand();
  ret <<= 32;
  ret |= xrand();
  return ret;
}


using Op = pair<string, vector<int>>;
vector<Op> prog;

void SET(int i, int j) { prog.push_back(Op("SET", {i, j})); }
void XOR(int i, int j, int k) { prog.push_back(Op("XOR", {i, j, k})); }
void AND(int i, int j, int k) { prog.push_back(Op("AND", {i, j, k})); }
void OR(int i, int j, int k) { prog.push_back(Op("OR", {i, j, k})); }
void NOT(int i, int j) { prog.push_back(Op("NOT", {i, j})); }
void LSH(int i, int x) { if (x != 0) prog.push_back(Op("LSH", {i, x})); }
void RSH(int i, int x) { if (x != 0) prog.push_back(Op("RSH", {i, x})); }

constexpr int V = 401;

void checkCost() {
  vector<int> dp(V, 0);
  for (const Op &op : prog) {
    const int len = op.second.size();
    int mx = 0;
    if (op.first == "LSH" || op.first == "RSH") {
      assert(len == 2);
      assert(1 <= op.second[0]); assert(op.second[0] < V);
      assert(0 <= op.second[1]); assert(op.second[1] < 64);
      chmax(mx, dp[op.second[0]]);
    } else {
      for (int i = 0; i < len; ++i) {
        assert(1 <= op.second[i]); assert(op.second[i] < V);
      }
      for (int i = 1; i < len; ++i) chmax(mx, dp[op.second[i]]);
    }
    dp[op.second[0]] = mx + 1;
  }
  const int cost = *max_element(dp.begin(), dp.end());
  cerr << "cost = " << cost << endl;
}

unsigned long long vals[V];
void exe(unsigned long long a, unsigned long long b) {
  memset(vals, 0, sizeof(vals));
  vals[1] = a;
  vals[2] = b;
  for (const Op &op : prog) {
    const auto &is = op.second;
    if (false) {}
    else if (op.first == "SET") vals[is[0]] = vals[is[1]];
    else if (op.first == "XOR") vals[is[0]] = vals[is[1]] ^ vals[is[2]];
    else if (op.first == "AND") vals[is[0]] = vals[is[1]] & vals[is[2]];
    else if (op.first == "OR" ) vals[is[0]] = vals[is[1]] | vals[is[2]];
    else if (op.first == "NOT") vals[is[0]] = ~vals[is[1]];
    else if (op.first == "LSH") vals[is[0]] <<= is[1];
    else if (op.first == "RSH") vals[is[0]] >>= is[1];
    else assert(false);
  }
}

int main() {
  int id = 1;
  const int A = id++;
  const int B = id++;
  
  constexpr int WORK_LEN = 128;
  vector<int> work(WORK_LEN, -1);
  for (int i = 0; i < WORK_LEN; ++i) work[i] = id++;
  
  // bs[e] := A[e] B
  vector<int> bs(64);
  for (int e = 0; e < 64; ++e) bs[e] = id++;
  {
    for (int e = 0; e < 64; ++e) {
      // A[e]
      SET(work[0], A);
      LSH(work[0], 63 - e);
      RSH(work[0], 63);
      // 2^f A[e]
      for (int f = 1; f < 64; ++f) {
        SET(work[f], work[0]);
        LSH(work[f], f);
      }
      // (2^64-1) A[e]
      for (int i = 0; i < 64 - 1; ++i) {
        OR(work[64 + i], work[i << 1], work[i << 1 | 1]);
      }
      AND(bs[e], work[2 * 64 - 2], B);
    }
  }
  
#ifdef LOCAL
  checkCost();
  for (int iter = 0; iter < 10; ++iter) {
    const auto iniA = gen();
    const auto iniB = gen();
    exe(iniA, iniB);
    for (int e = 0; e < 64; ++e) {
      assert(vals[bs[e]] == ((iniA >> e & 1) ? iniB : 0));
    }
  }
#endif
  
  // css[e]: to be multiplied 2^e
  vector<vector<int>> css(64);
  for (int e = 0; e < 64; ++e) {
    css[e].push_back(bs[e]);
  }
  for (; ; ) {
// cerr<<"css = "<<css<<endl;
    int tot = 0, rem = 0;
    for (int e = 0; e < (int)css.size(); ++e) {
      tot += (int)css[e].size();
      rem += (int)css[e].size() % 3;
    }
    if (tot <= 2) {
      break;
    }
    if (rem >= 3) {
      vector<vector<int>> dss(1);
      for (int e = 0; e < (int)css.size(); ++e) {
        for (const int c : css[e]) {
          LSH(c, e);
          dss[0].push_back(c);
        }
      }
      css = dss;
    }
    const int cssLen = css.size();
    vector<vector<int>> dss(cssLen + 1);
    for (int e = 0; e < cssLen; ++e) {
      const int csLen = css[e].size();
      for (int i = 0; i < csLen; ) {
        if (i + 3 <= csLen) {
          // full adder
          const int x0 = css[e][i];
          const int x1 = css[e][i + 1];
          const int x2 = css[e][i + 2];
          const int y0 = id++;
          const int y1 = id++;
          XOR(y0, x0, x1);
          XOR(y0, y0, x2);
          AND(y1, x0, x1);
          AND(x0, x0, x2);
          AND(x1, x1, x2);
          XOR(y1, y1, x0);
          XOR(y1, y1, x1);
          dss[e].push_back(y0);
          dss[e + 1].push_back(y1);
          i += 3;
        } else {
          dss[e].push_back(css[e][i]);
          i += 1;
        }
      }
    }
    for (; !dss.empty() && dss.back().empty(); dss.pop_back()) {}
    css = dss;
  }
  assert(css.size() == 2);
  assert(css[0].size() == 1);
  assert(css[1].size() == 1);
  const int a = css[0][0];
  const int b = css[1][0];
  LSH(b, 1);
  
#ifdef LOCAL
  checkCost();
  for (int iter = 0; iter < 10; ++iter) {
    const auto iniA = gen();
    const auto iniB = gen();
    exe(iniA, iniB);
    assert(vals[a] + vals[b] == iniA * iniB);
  }
#endif
  
  // a + b
  // carry[e] = (\OR[f<e] ((a[f] & b[f]) & \AND[f<g<e] (a[g] ^ b[g])))
  vector<int> Xors(64, -1), Ands(64, -1);
  for (int i = 0; i < 64; ++i) {
    Xors[i] = work[i << 1];
    Ands[i] = work[i << 1 | 1];
  }
  XOR(Xors[0], a, b);
  AND(Ands[0], a, b);
  for (int i = 1; i < 64; ++i) {
    SET(Xors[i], Xors[0]);
    SET(Ands[i], Ands[0]);
    LSH(Xors[i], i);
    LSH(Ands[i], i);
  }
  /*
    Ands[1]
    Xors[1] & Ands[2]
    Xors[1] & Xors[2] & Ands[3]
    ...
    Xors[1] & ... & Xors[62] & Ands[63]
  */
  auto xs = Xors, ys = Ands;
  xs[0] = id++;
  // xs[0] = ~0
  NOT(xs[0], xs[0]);
  ys[0] = id++;
  // ys[0] = 0
  for (int d = 1; d < 64; d <<= 1) {
    for (int i = 0; i < 64; i += d << 1) {
      // (x0, y0), (x1, y1) -> (x0 & x1, y0 | (x0 & y1))
      const int x0 = xs[i], x1 = xs[i + d];
      const int y0 = ys[i], y1 = ys[i + d];
      AND(y1, y1, x0);
      OR(y0, y0, y1);
      AND(x0, x0, x1);
    }
  }
  XOR(A, Xors[0], ys[0]);
#define a do_not_use_a
#define b do_not_use_b
  
  for (const Op &op : prog) {
    printf("%s", op.first.c_str());
    for (const int i : op.second) {
      printf(" %d", i);
    }
    puts("");
  }
  
#ifdef LOCAL
  cerr << "id = " << id << endl;
  checkCost();
  for (int iter = 0; iter < 10; ++iter) {
    const auto iniA = gen();
    const auto iniB = gen();
    exe(iniA, iniB);
    assert(vals[1] == iniA * iniB);
  }
#endif
  
  return 0;
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 3ms
memory: 4068kb

input:

main

output:

SET 3 1
LSH 3 63
RSH 3 63
SET 4 3
LSH 4 1
SET 5 3
LSH 5 2
SET 6 3
LSH 6 3
SET 7 3
LSH 7 4
SET 8 3
LSH 8 5
SET 9 3
LSH 9 6
SET 10 3
LSH 10 7
SET 11 3
LSH 11 8
SET 12 3
LSH 12 9
SET 13 3
LSH 13 10
SET 14 3
LSH 14 11
SET 15 3
LSH 15 12
SET 16 3
LSH 16 13
SET 17 3
LSH 17 14
SET 18 3
LSH 18 15
SET 19 3
L...

result:

ok Correct: depth=60