QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#290470 | #4820. Kitten's Computer | ucup-team087# | AC ✓ | 3ms | 4068kb | C++14 | 7.7kb | 2023-12-25 01:54:21 | 2023-12-25 01:54:21 |
Judging History
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