#include "abc.h"
#include <bits/stdc++.h>
using namespace std;
// you may find the definitions useful
const int OP_ZERO = 0; // f(OP_ZERO, x0, x1) = 0
const int OP_NOR = 1; // f(OP_NOR, x0, x1) = !(x0 || x1)
const int OP_GREATER = 2; // f(OP_GREATER, x0, x1) = (x0 > x1)
const int OP_NOT_X1 = 3; // f(OP_NOT_X1, x0, x1) = !x1
const int OP_LESS = 4; // f(OP_LESS, x0, x1) = (x0 < x1)
const int OP_NOT_X0 = 5; // f(OP_NOT_X0, x0, x1) = !x0
const int OP_XOR = 6; // f(OP_XOR, x0, x1) = (x0 ^ x1)
const int OP_NAND = 7; // f(OP_NAND, x0, x1) = !(x0 && x1)
const int OP_AND = 8; // f(OP_AND, x0, x1) = (x0 && x1)
const int OP_EQUAL = 9; // f(OP_EQUAL, x0, x1) = (x0 == x1)
const int OP_X0 = 10; // f(OP_X0, x0, x1) = x0
const int OP_GEQ = 11; // f(OP_GEQ, x0, x1) = (x0 >= x1)
const int OP_X1 = 12; // f(OP_X1, x0, x1) = x1
const int OP_LEQ = 13; // f(OP_LEQ, x0, x1) = (x0 <= x1)
const int OP_OR = 14; // f(OP_OR, x0, x1) = (x0 || x1)
const int OP_ONE = 15; // f(OP_ONE, x0, x1) = 1
const int nameSize = 20;
const int numSize = 16;
int conv(const char name[]){
string nam = "";
for(int i = 0;i<5;i++){
if(name[i]<='z'&&name[i]>='a'){
nam+=name[i];
}
else{
break;
}
}
int ans = 0;
for(char c : nam){
ans*=27;
ans+=(c-'a'+1);
}
return ans;
}
// Alice
int // returns la
alice(
/* in */ const int n,
/* in */ const char names[][5],
/* in */ const unsigned short numbers[],
/* out */ bool outputs_alice[]
) {
int ind = 0;
for(int i = 0;i<n;i++){
int name = conv(names[i]);
for(int j = 0;j<nameSize;j++){
if((1<<j)&name){
outputs_alice[ind++]=1;
}
else{
outputs_alice[ind++]=0;
}
}
for(int j = 0;j<numSize;j++){
if((1<<j)&numbers[i]){
outputs_alice[ind++]=1;
}
else{
outputs_alice[ind++]=0;
}
}
}
return ind;
}
// Bob
int // returns lb
bob(
/* in */ const int m,
/* in */ const char senders[][5],
/* in */ const char recipients[][5],
/* out */ bool outputs_bob[]
) {
int ind = 0;
for(int i = 0;i<m;i++){
int send = conv(senders[i]);
int recv = conv(recipients[i]);
for(int j = 0;j<nameSize;j++){
if((1<<j)&send){
outputs_bob[ind++]=1;
}
else{
outputs_bob[ind++]=0;
}
}
for(int j = 0;j<nameSize;j++){
if((1<<j)&recv){
outputs_bob[ind++]=1;
}
else{
outputs_bob[ind++]=0;
}
}
}
return ind;
}
// Circuit
int // returns l
circuit(
/* in */ const int la,
/* in */ const int lb,
/* out */ int operations[],
/* out */ int operands[][2],
/* out */ int outputs_circuit[][16]
) {
int n = la/(nameSize+numSize);
int m = lb/(nameSize*2);
int ind = 0;
vector<int>people[n];
vector<int>nums[n];
for(int i = 0;i<n;i++){
for(int j = 0;j<nameSize;j++){
people[i].push_back(ind++);
}
for(int j = 0;j<numSize;j++){
nums[i].push_back(ind++);
}
}
array<vector<int>,2> msgs[m];
for(int i = 0;i<m;i++){
for(int j = 0;j<nameSize;j++){
msgs[i][0].push_back(ind++);
}
for(int j = 0;j<nameSize;j++){
msgs[i][1].push_back(ind++);
}
}
assert(ind==la+lb);
auto checkEqual = [&] (vector<int>a, vector<int>b){
assert(a.size()==b.size());
vector<int>ans(a.size());
for(int i = 0;i<a.size();i++){
operations[ind]=OP_EQUAL;
operands[ind][0] = a[i];
operands[ind][1] = b[i];
ans[i]=ind;
ind++;
}
int las = ans[0];
for(int i = 1;i<ans.size();i++){
operations[ind]=OP_AND;
operands[ind][0]=las;
operands[ind][1]=ans[i];
las=ind;
ind++;
}
return las;
};
auto mult1 = [&] (vector<int>a, int b){
//if b is 1 puts a else puts 0
vector<int>ans(a.size());
for(int i = 0;i<a.size();i++){
operations[ind]=OP_AND;
operands[ind][0]=a[i];
operands[ind][1]=b;
ans[i]=ind;
ind++;
}
return ans;
};
auto orsum = [&] (vector<int>a, vector<int>b){
assert(a.size()==b.size());
vector<int>ans(a.size());
for(int i = 0;i<a.size();i++){
ans[i]=ind;
operations[ind]=OP_OR;
operands[ind][0]=a[i];
operands[ind][1]=b[i];
ind++;
}
return ans;
};
auto add = [&] (vector<int>a, vector<int>b) {
assert(a.size()==b.size());
vector<int>ans(a.size());
ans[0]=ind;
operations[ind]=OP_XOR;
operands[ind][0]=a[0];
operands[ind][1]=b[0];
ind++;
int carry = ind;
operations[ind]=OP_AND;
operands[ind][0]=a[0];
operands[ind][1]=b[0];
ind++;
for(int i = 1;i<ans.size();i++){
operations[ind]=OP_XOR;
operands[ind][0]=a[i];
operands[ind][1]=b[i];
ind++;
operations[ind]=OP_XOR;
operands[ind][0]=ind-1;
operands[ind][1]=carry;
ans[i]=ind;
ind++;
//set carry for next bit
operations[ind]=OP_AND;
operands[ind][0]=a[i];
operands[ind][1]=b[i];
int ab = ind;
ind++;
operations[ind]=OP_AND;
operands[ind][0]=carry;
operands[ind][1]=b[i];
int bc = ind;
ind++;
operations[ind]=OP_AND;
operands[ind][0]=a[i];
operands[ind][1]=carry;
int ac = ind;
ind++;
//xor these 3
operations[ind]=OP_XOR;
operands[ind][0]=ab;
operands[ind][1]=ac;
ind++;
operations[ind]=OP_XOR;
operands[ind][0]=ind-1;
operands[ind][1]=bc;
carry=ind;
ind++;
}
return ans;
};
vector<vector<int>>buckets[n];
for(int i = 0;i<m;i++){
//first find what persons number is being transferred for this message
vector<int>inds(n);
for(int s = 0;s<n;s++){
inds[s]=checkEqual(people[s],msgs[i][0]);
}
///one of inds is 1 that persons number is being transferred rn
///multiple all number by respective bit and then or all the results
vector<int>curnums[n];
for(int s = 0;s<n;s++){
curnums[s]=mult1(nums[s],inds[s]);
}
///now or all nums here and put in one place
vector<int>ord = curnums[0];
for(int s = 1;s<n;s++){
ord=orsum(ord,curnums[s]);
}
//ord is the current number that is being given to recipent
//now find which person is receiving
for(int s = 0;s<n;s++){
inds[s]=checkEqual(people[s],msgs[i][1]);
}
//inds now stores which person has received it
//multiple ord by inds for each of n and put the number in bucket of nth
for(int e = 0;e<n;e++){
buckets[e].push_back(mult1(ord,inds[e]));
}
}
///now each of buckets need to be added simply.
if(buckets[0].size()==0){
assert(m==0);
///must simply output 0
vector<int>ans(numSize);
for(int j = 0;j<numSize;j++){
operations[ind]=OP_ZERO;
operands[ind][0]=0;
operands[ind][0]=1;
ind++;
ans[j]=ind;
}
for(int i = 0;i<n;i++){
for(int j = 0;j<numSize;j++){
outputs_circuit[i][j]=ans[j];
}
}
return ind;
}
for(int i = 0;i<n;i++){
vector<int>curans = buckets[i][0];
for(int j = 1;j<buckets[i].size();j++){
curans=add(curans,buckets[i][j]);
}
for(int j = 0;j<numSize;j++){
outputs_circuit[i][j]=curans[j];
}
}
return ind;
}