DS Certi (Pro) 기출 문제 - jjin-choi/study_note GitHub Wiki
- chaining 을 통해서 probing 을 해주어 하기 때문에 이를 담고 있는 정보가 있는 값을 저장 해야 한다.
- 객체 자체를 넣어도 되고, 이를 담고 있는 table 의 index 를 넣어 주어도 됨.
- ex) id 범위가 1 ~ 1,000,000,000 일 경우 SIZE = 1<<16 / MASK = SIZE -1 로 하고 hash table 의 index = id & MASK 로 해주면 됨.
- hash 안에서는 겹치는 경우가 당연히 있기 때문에 table 안에는 실제 id 값 저장
- key -> code -> hidx -> probing -> 원하는 정보
- indexing (문자열, 큰 자리 수, 숫자 배열 등)
- direct address table : 태니지, 소문자 4자
- hash
- 배열에 순선대로 저장 : 케이크, 총 100개 이하
- indexing (문자열, 큰 자리 수, 숫자 배열 등)
- hash key : data 의 고유 값을 나타낼 수 있는 정보로 설정
- hash function : code 생성 (unsigned int / long long 혹은 hash index 로 변환. K 진법... )
- 소문자만 있을 경우 : 27진법. 대소문자일 경우 53진법
- hash size : chaining 시 최소 data 수 혹은 제곱. SIZE = 1 << x. MASK = SIZE - 1
- linear search : 나올 수 있는 종류가 적을 때
- direct address table : 소문자 4자리 정도이면 k 진법을 정확히 쓰면 됨. (ex. 27진법)
-
linked list 입력 순 (array) ※ worst 와 average 가 차이가 있음
- 삽입 삭제 업데이트 : O(1)
- 쿼리 : O(n) * 쿼리 수
-
linked list 정렬 (array) ※ worst 와 average 가 거의 동일
- 삽입 업데이트 : O(n)
- 쿼리 : O(n) * 쿼리 수
-
heap : log n
-
heap 정렬을 쓰게 되면 구성이 안된 것을 매번 구성해야 하므로 n long n 만큼의 시간이 들기 때문에 linear search 가 낫다.
-
ex) 나튜브 문제
- member 수 : 10,000 video 수 : 40,000
- add() : 40,000 / remove() : 20,000 / update() : 20,000 / query : 4000, 4000
- linked list 입력 순으로 하면
- 삽입 삭제 업데이트 : O(1)
- 쿼리 : O(n * 10) * 쿼리 수 = O(40,000 * 4000) = O (1억 6천 * a) + O(10 * 10000 * 40)
- 이를 heap 으로 하면
- 삽입 삭제 업데이트 : O(log n) * query = O (16 * 80,000)
- 쿼리 : O(n* 10) * 쿼리 수 = O(20 * 16 * 4000)
- 따라서 heap 으로 하는 게 좋다.
-
ex) 카톡카톡 문제
-
member 수 : 10,000
-
makeonoff() : 10,000 / 친구 관계() - 삽입 삭제 : 20,000 / 대화() : 20,000 / send() : 50,000 / getToList : 20,000 / getToPartner : 1,000
-
우선순위 : 첫번재는 online. 두번째는 주고받은 메시지가 많은 것. 세번째는 aid 가 작을 수록 우선.
- 우선 순위 변경 조건 : makeonof 와 + send 함수 호출 시. 따라서 모든 친구들을 돌면서 우선순위를 변경해줘야 한다.
- makeonof 호출 수 (10,000) * 친구 수 / send 호출 수 : 50,000 / 우선 순위 query (1000) + 삽입 삭제 20,000 번
-
linked list 입력 순으로 하면
- 삽입 삭제 업데이트 : O(1) * 쿼리 수
- 우선순위 쿼리 : O(n * 5) * 쿼리 수 = O(5천만)
-
이를 heap 으로 하면
- 삽입 삭제 업데이트 : O(log n) * query = O (14 * (10,000 * n + 50000+ 20000))
- 최악의 경우 n 은 10000 이다.
- 쿼리 : O(n* 10) * 쿼리 수 = O(5 * 14 * 1000)
-
이 경우에는 linked list 로 하는 게 좋다.
-
-
업데이트 되는 회수가 많아서 계속 변경해줘야 한다면 heap 으로 할 경우 오래걸린다.
-
업데이트가 적게 이루어 진다면 linear search 를 해줘도 좋다. (linked list 를 써서)
-
우선 순위 구할 때 생각보다 linear search 로 할 경우가 많다. 생각보다 시간 안에 들어온다면 heap 쓰지 말고.. !
- id 값들이 범위가 너무 큰 경우에는 table 을 써보자
- hash 와 hash 의 node 를 가리키는 linked list 를 써보자 (LRU 처럼..)
- 위와 같이 쓸 때에는 같은 struct 를 가리키고 있으면 됨.
- str 를 int 로 바꿀 때 늘 주의하자 !! (ex. -'a' + 1)
- dummy 노드가 있을 때에는 for 문의 시작점이 달라지는 것도 주의
- hash 에서 chaining 을 써야 하는 경우인지 아닌지에 따라 probing 코드 잘 짜기
/////////// user code ///////////
const int MAX = (int)(1e5 + 5);
template <typename _type>
void _swap(_type &x, _type &y) {
_type temp = x; x = y; y = temp;
}
struct Member {
int id, frequency;
};
bool _comp_0(Member x, Member y) {
if (x.frequency == y.frequency) return x.id < y.id;
return x.frequency < y.frequency;
}
bool _comp_1(Member x, Member y) {
if (x.frequency == y.frequency) return x.id < y.id;
return x.frequency < y.frequency;
}
bool _comp_2(Member x, Member y) {
if (x.frequency == y.frequency)
return x.id > y.id;
return x.frequency > y.frequency;
}
struct _priority_queue {
int hn;
int sum;
int pos[MAX + MAX];
Member heap[MAX];
bool(*comp) (Member, Member);
void init(int mode) {
hn = 0;
sum = 0;
if (mode == 0) comp = _comp_0;
if (mode == 1) comp = _comp_0;
if (mode == 2) comp = _comp_2;
}
void swap(int x, int y) {
_swap(heap[x], heap[y]);
_swap(pos[heap[x].id], pos[heap[y].id]);
}
void up(int h_idx) {
for (int c = h_idx; c > 1; c /= 2) {
if (comp(heap[c], heap[c / 2])) swap(c, c / 2);
else break;
}
}
void down(int h_idx) {
for (int c = h_idx * 2; c <= hn; c *= 2) {
if (c < hn && !comp(heap[c], heap[c + 1])) c++;
if (comp(heap[c], heap[c / 2])) swap(c, c / 2);
else break;
}
}
void push(Member newmem) {
heap[++hn] = newmem;
pos[newmem.id] = hn;
up(hn);
sum += newmem.frequency;
}
Member pop() {
Member ret = heap[1];
swap(1, hn--);
down(1);
sum -= ret.frequency;
return ret;
}
Member erase(int h_idx) {
Member ret = heap[h_idx];
swap(h_idx, hn--);
up(h_idx), down(h_idx);
sum -= ret.frequency;
return ret;
}
Member top() { return heap[1]; }
} max_pq, min_pq, front_pq, back_pq;
Member median;
// [Note!] 중간중간 median 이 바뀌므로 꼭 shift 를 해주자
void shift_median() {
if (front_pq.hn > back_pq.hn + 1) {
Member out = front_pq.pop();
back_pq.push(out);
}
else if (front_pq.hn < back_pq.hn) {
Member out = back_pq.pop();
front_pq.push(out);
}
median = front_pq.top();
}
void push_for_median(Member newmem) {
if (_comp_1(newmem, median))
front_pq.push(newmem);
else
back_pq.push(newmem);
shift_median();
}
void erase_member(Member obj) {
min_pq.erase(min_pq.pos[obj.id]);
max_pq.erase(max_pq.pos[obj.id]);
}
void addMember(Member obj) {
max_pq.push(obj);
min_pq.push(obj);
push_for_median(obj);
}
int removeMembers(int mode) {
if (mode == 0) {
Member out = min_pq.pop();
max_pq.erase(max_pq.pos[out.id]);
if (_comp_1(out, median))
front_pq.erase(front_pq.pos[out.id]);
else
back_pq.erase(back_pq.pos[out.id]);
shift_median();
return out.id;
}
if (mode == 1) {
if (front_pq.hn == back_pq.hn) {
Member out_1 = front_pq.pop();
Member out_2 = back_pq.pop();
erase_member(out_1);
erase_member(out_2);
shift_median();
return out_1.id + out_2.id;
}
else {
Member out = front_pq.pop();
erase_member(out);
shift_median();
return out.id;
}
}
if (mode == 2) {
Member out = max_pq.pop();
min_pq.erase(min_pq.pos[out.id]);
if (_comp_1(out, median))
front_pq.erase(front_pq.pos[out.id]);
else
back_pq.erase(back_pq.pos[out.id]);
shift_median();
return out.id;
}
}
void getSum(int sum[]) {
sum[0] = front_pq.sum;
sum[1] = back_pq.sum;
if (front_pq.hn != back_pq.hn)
sum[0] -= median.frequency;
}
void userInit(int memberCount, Member members[]) {
max_pq.init(2);
min_pq.init(0);
front_pq.init(2);
back_pq.init(0);
for (int m = 0; m < memberCount; m++) {
max_pq.push(members[m]);
min_pq.push(members[m]);
}
front_pq.push(members[0]);
median = members[0];
for (int m = 1; m < memberCount; m++)
push_for_median(members[m]);
}
/////////// main code ///////////
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
const int IDLIMIT = (int)1e5;
const int FREQUENCYLIMIT = IDLIMIT + 1;
const int RANDMULTI = 0x694F1;
const int RANDADD = 0x26A29F;
const int RANDMOD = ~(1 << 31);
const int REMOVELIMIT = 6;
const int AVGLIMIT = 4;
struct Member {
int id, frequency;
};
extern void userInit(int memberCount, Member members[]);
extern void addMember(Member obj);
extern int removeMembers(int mode);
extern void getSum(int sum[]);
static int randSeed;
static int memberCount, orderCount;
static int idChk[IDLIMIT];
static int passCount;
static bool continuous;
static int getRandNum(void) {
randSeed = randSeed * RANDMULTI + RANDADD;
return randSeed & RANDMOD;
}
static int getFrequency() {
int frequency;
do {
frequency = getRandNum() % FREQUENCYLIMIT;
} while (frequency == FREQUENCYLIMIT - 1);
return frequency;
}
static void mainInit(int tc, int n) {
Member members[50001];
for (int i = 0; i < n; ++i) {
int id = getRandNum() % IDLIMIT;
int frequency = getFrequency();
while (idChk[id] == tc) {
id = (id + 1) % IDLIMIT;
}
idChk[id] = tc;
members[i].id = id;
members[i].frequency = frequency;
}
userInit(n, members);
}
static void addFunc(int tc) {
Member Member;
int id = getRandNum() % IDLIMIT;
int frequency = getFrequency();
while (idChk[id] == tc) {
id = (id + 1) % IDLIMIT;
}
idChk[id] = tc;
Member.id = id;
Member.frequency = frequency;
addMember(Member);
}
static int run(int tc) {
passCount = 0;
bool continuous = true;
mainInit(tc, memberCount);
while (orderCount--) {
int order = getRandNum() % (REMOVELIMIT + AVGLIMIT);
if (continuous && order < AVGLIMIT) {
int sum[2];
int ansSum[2];
getSum(sum);
scanf("%d%d", &ansSum[0], &ansSum[1]);
if (sum[0] == ansSum[0] && sum[1] == ansSum[1]) {
++passCount;
}
continuous = false;
}
else {
int K = getRandNum() % 3;
int retId, correctId;
retId = removeMembers(K);
scanf("%d", &correctId);
if (retId == correctId) {
++passCount;
}
addFunc(tc);
if (K == 1 && memberCount % 2 == 0) {
addFunc(tc);
}
continuous = true;
}
}
return passCount;
}
int main(void) {
freopen("input.txt", "r", stdin);
int TestCnt;
int ansCount, totalScore = 0;
scanf("%d", &TestCnt);
setbuf(stdout, NULL);
for (int tc = 1; tc <= TestCnt; ++tc) {
scanf("%d%d%d%d", &randSeed, &memberCount, &orderCount, &ansCount);
if (run(tc) == ansCount) {
printf("#%d 100\n", tc);
totalScore += 100;
}
else {
printf("#%d 0\n", tc);
}
}
printf("Total Score = %d\n", totalScore / TestCnt);
return 0;
}
/////////// user code ///////////
const int MAX = (int)(1e4 + 5);
const int SIZE = 1 << 14;
const int MASK = SIZE - 1;
int h_cnt, b_cnt;
int strcmp(const char* s, const char* t) {
while (*s && *s == *t) ++s, ++t;
return *s - *t;
}
int strlen(const char* s, int len = 0) {
while (s[len]) ++len;
return len;
}
void strcpy(char* dest, const char* src) {
while ((*dest++ = *src++));
}
struct _book {
char title[25], author[25], genre[25];
int cnt, sum;
} books[MAX];
struct _hash {
_book book;
_hash* t_next;
_hash* a_next;
_hash* g_next;
_hash* alloc(_book _newbook, _hash* _t_next, _hash* _a_next, _hash* _g_next) {
book = _newbook, t_next = _t_next, a_next = _a_next, g_next = _g_next;
return this;
}
} h_buff[SIZE], *t_head[SIZE], *a_head[SIZE], *g_head[SIZE];
bool compare_str(_book _x, _book _y, int _type) {
char x[25], y[25];
if (_type == 1) {
strcpy(x, _x.author);
strcpy(y, _y.author);
}
if (_type == 2) {
strcpy(x, _x.genre);
strcpy(y, _y.genre);
}
int x_len = strlen(x);
int y_len = strlen(y);
int max = (x_len > y_len) ? x_len : y_len;
for (int m = 0; m < max; m++) {
if (x[m] < y[m]) return true;
else if (x[m] > y[m]) return false;
}
x_len = strlen(_x.title);
y_len = strlen(_y.title);
max = (x_len > y_len) ? x_len : y_len;
for (int m = 0; m < max; m++) {
if (_x.title[m] < _y.title[m]) return true;
else if (_x.title[m] > _y.title[m]) return false;
}
}
struct _priority_queue {
int hn;
int type;
_book heap[MAX];
void init(int _type) { hn = 0, type = _type; }
void swap(_book &x, _book &y) { _book temp = x; x = y; y = temp; }
bool comp(_book x, _book y) {
if (x.sum == y.sum) return compare_str(x, y, type);
return x.sum > y.sum;
}
void push(_book newbook) {
heap[++hn] = newbook;
for (int c = hn; c > 1; c /= 2) {
if (comp(heap[c], heap[c / 2])) swap(heap[c], heap[c / 2]);
else break;
}
}
_book pop() {
_book ret = heap[1];
swap(heap[1], heap[hn--]);
for (int c = 2; c <= hn; c *= 2) {
if (c < hn && !comp(heap[c], heap[c + 1]))c++;
if (comp(heap[c], heap[c / 2])) swap(heap[c], heap[c / 2]);
else break;
}
return ret;
}
} max_pq;
int hash_func(char str[]) {
int ret = 0;
for (int c = 0; str[c]; c++)
ret = (ret * 27 + (str[c] - 'a')) & MASK;
return ret;
}
void init() {
b_cnt = 0, h_cnt = 0;
for (int s = 0; s < SIZE; s++)
t_head[s] = 0, a_head[s] = 0, g_head[s] = 0;
}
_hash* probing(char title[]) {
int idx = hash_func(title);
for (_hash* p = t_head[idx]; p; p = p->t_next)
if (!strcmp(p->book.title, title)) return p;
return 0;
}
void inputBook(char title[], char author[], char genre[], int cnt) {
int t_idx = hash_func(title);
int a_idx = hash_func(author);
int g_idx = hash_func(genre);
_hash* p = probing(title);
if (!p) {
strcpy(books[b_cnt].title, title);
strcpy(books[b_cnt].author, author);
strcpy(books[b_cnt].genre, genre);
books[b_cnt].cnt = cnt;
t_head[t_idx] = g_head[g_idx] = a_head[a_idx] = h_buff[h_cnt].alloc(books[b_cnt++], t_head[t_idx], a_head[a_idx], g_head[g_idx]);
h_cnt++;
}
else
p->book.cnt += cnt;
}
void loanBook(char title[], int cnt) {
_hash* p = probing(title);
if (p) {
int upper_cnt = (cnt > p->book.cnt) ? p->book.cnt : cnt;
p->book.cnt -= upper_cnt;
p->book.sum += upper_cnt;
}
}
int getLoanableCnt(int type, char str[]) {
int ret = 0;
if (type == 0) {
int idx = hash_func(str);
_hash* p = probing(str);
if (!p) return 0;
ret = p->book.cnt;
}
if (type == 1) {
int idx = hash_func(str);
for (_hash* p = a_head[idx]; p; p = p->a_next)
if (!strcmp(p->book.author, str)) ret += p->book.cnt;
}
if (type == 2) {
int idx = hash_func(str);
for (_hash* p = g_head[idx]; p; p = p->g_next)
if (!strcmp(p->book.genre, str)) ret += p->book.cnt;
}
return ret;
}
void recommendBook(int type, char str[], char(*userStr)[22]) {
int idx = hash_func(str);
max_pq.init(type);
if (type == 1) {
for (_hash* p = a_head[idx]; p; p = p->a_next) {
// [Note!] hash chaining 을 쓸 때에는 꼭 실제 값과 같은지 비교해야 함.
if (p->book.cnt && !strcmp(p->book.author, str)) max_pq.push(p->book);
}
}
if (type == 2) {
for (_hash* p = g_head[idx]; p; p = p->g_next) {
if (p->book.cnt && !strcmp(p->book.genre, str)) max_pq.push(p->book);
}
}
_book book = max_pq.pop();
strcpy(userStr[0], book.title);
strcpy(userStr[1], book.author);
strcpy(userStr[2], book.genre);
}
/////////// main code ///////////
_CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdio.h>
extern void init();
extern void inputBook(char title[], char author[], char genre[], int cnt);
extern void loanBook(char title[], int cnt);
extern int getLoanableCnt(int type, char str[]);
extern void recommendBook(int type, char str[], char(*userStr)[22]);
static unsigned int SEED;
static int myrand() {
SEED = SEED * 0x694f1 + 0x26a29f;
return SEED & 0x7fffffff;
}
static void genString(int type, char* str) {
int maxLen[] = { 20, 10, 10 };
int slen = myrand() % (maxLen[type] - 4) + 5;
for (int i = 0; i < slen; ++i)
str[i] = myrand() % 26 + 'a';
str[slen] = 0;
}
static int mstrcmp(const char* s, const char* t) {
while (*s && *s == *t)
++s, ++t;
return *s - *t;
}
static int run() {
int QN, cmd, score = 100;
int type, ans, cnt, ret;
char str[3][22];
char userStr[3][22];
scanf("%d", &QN);
for (int i = 1; i <= QN; ++i) {
scanf("%d ", &cmd);
switch (cmd) {
case 0:
init();
break;
case 1:
for (int i = 0; i < 3; ++i) {
scanf("%d", &SEED);
genString(i, str[i]);
}
scanf("%d", &cnt);
inputBook(str[0], str[1], str[2], cnt);
break;
case 2:
scanf("%d", &SEED);
genString(0, str[0]);
scanf("%d", &cnt);
loanBook(str[0], cnt);
break;
case 3:
scanf("%d %d", &type, &SEED);
genString(type, str[type]);
scanf("%d", &ans);
ret = getLoanableCnt(type, str[type]);
if (ret != ans) {
score = 0;
}
break;
case 4:
scanf("%d", &type);
for (int i = 0; i < 3; ++i) {
scanf("%d", &SEED);
genString(i, str[i]);
}
recommendBook(type, str[type], userStr);
if (mstrcmp(userStr[0], str[0]) != 0
|| mstrcmp(userStr[1], str[1]) != 0
|| mstrcmp(userStr[2], str[2]) != 0) {
score = 0;
}
break;
}
}
return score;
}
int main() {
setbuf(stdout, NULL);
freopen("input.txt", "r", stdin);
int TC, score = 100, totalScore = 0;
scanf("%d", &TC);
for (int tc = 1; tc <= TC; tc++) {
score = run();
totalScore += score;
printf("#Testcase %2d : %d\n", tc, score);
}
printf("#Total Score : %d\n", totalScore / TC);
return 0;
}
/////////// user code ///////////
/////////// main code ///////////
/////////// user code ///////////
#define THIS_CODE_IS_RUNNING
#ifdef THIS_CODE_IS_RUNNING
#define MAXLEN (5)
const int MAX_C = (int)(1e5 + 5);
const int SIZE = (27 * 27 * 27 * 27 + 5);
const int MAX_U = (int)(3e4 + 5);
int users[SIZE];
int h_cnt, u_cnt;
struct _node {
int id, user, server;
int tick, point;
_node* prev;
_node* next;
_node* alloc(int _id, int _user, int _server, int _tick, int _point, _node* _prev, _node* _next) {
id = _id, user = _user, server = _server, tick = _tick, point = _point;
prev = _prev, next = _next;
if (prev) prev->next = this;
if (next) next->prev = this;
return this;
}
_node* erase() {
// [Note!] 실수하지 말자.. this->next, this->prev
if (prev) prev->next = this->next;
if (next) next->prev = this->prev;
return prev;
}
} h_buff[SIZE + SIZE], *u_head[MAX_U], *c_list[MAX_C];
// u_head 의 index 는 users 테이블을 이용하여 최대 3만까지만 계산하도록 한다.
int str_to_int(char str[]) {
int ret = 0;
for (int i = 0; str[i]; i++)
// [Note!] 'a' 를 해주어야 원하는 크기 배열 사용 가능 . +1 도 해주어야 중복 제거
ret = ret * 27 + (str[i] - 'a') + 1;
return ret;
}
void userInit() {
h_cnt = 0, u_cnt = 0;
for (int c = 0; c < MAX_C; c++) c_list[c] = 0;
for (int u = 0; u < SIZE; u++) users[u] = 0;
for (int u = 0; u < MAX_U; u++) u_head[u] = h_buff[h_cnt++].alloc(0, 0, 0, 0, 0, 0, 0);
}
void create(int tick, char userName[MAXLEN], char serverName[MAXLEN], int charID, int point) {
int user = str_to_int(userName);
int server = str_to_int(serverName);
if (!users[user])
users[user] = ++u_cnt;
int u_idx = users[user];
c_list[charID] = h_buff[h_cnt++].alloc(charID, user, server, tick, point, u_head[u_idx], u_head[u_idx]->next);
}
int destroy(int tick, int charID) {
int ret = c_list[charID]->point;
c_list[charID]->erase();
c_list[charID] = 0;
return ret;
}
void update_tick(int tick, int charID) {
int user = c_list[charID]->user;
int server = c_list[charID]->server;
int point = c_list[charID]->point;
int u_idx = users[user];
c_list[charID]->erase(); c_list[charID] = 0;
c_list[charID] = h_buff[h_cnt++].alloc(charID, user, server, tick, point, u_head[u_idx], u_head[u_idx]->next);
}
int numToNum(int tick, int giverID, int recieverID, int point) {
_node* giver = c_list[giverID];
_node* receiver = c_list[recieverID];
if (!c_list[giverID] || !c_list[recieverID] || giver->point < point) {
return -1;
}
giver->tick = tick, giver->point -= point;
receiver->tick = tick, receiver->point += point;
update_tick(tick, giverID);
update_tick(tick, recieverID);
return receiver->point;
}
int numToName(int tick, int giverID, char recieverName[MAXLEN], int point) {
_node* giver = c_list[giverID];
int user = str_to_int(recieverName);
int u_idx = users[user];
_node* receiver = u_head[u_idx]->next;
if (!c_list[giverID] || !receiver || giver->point < point) {
return -1;
}
giver->tick = tick, giver->point -= point;
receiver->tick = tick, receiver->point += point;
update_tick(tick, giverID);
update_tick(tick, receiver->id);
return receiver->point;
}
void payBonusPoint(int tick, char serverName[MAXLEN], int point) {
int server = str_to_int(serverName);
for (int u = 0; u <= u_cnt; u++) {
// [Note!] dummy node 가 있을 때에는 항상 next 부터 시작
for (_node* p = u_head[u]->next; p; p = p->next) {
if (p->server == server) {
p->point += point;
update_tick(tick, p->id);
break;
}
}
}
}
#endif
/////////// main code ///////////
#define THIS_CODE_IS_RUNNING
#ifdef THIS_CODE_IS_RUNNING
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdio.h>
#define INIT 1
#define CREATE 2
#define DESTROY 3
#define NUMTONUM 4
#define NUMTONAME 5
#define BONUSPOINT 6
#define MAX_LEN 5
extern void userInit();
extern void create(int tick, char userName[MAX_LEN], char serverName[MAX_LEN], int charID, int point);
extern int destroy(int tick, int charID);
extern int numToNum(int tick, int giverID, int recieverID, int point);
extern int numToName(int tick, int giverID, char recieverName[MAX_LEN], int point);
extern void payBonusPoint(int tick, char serverName[MAX_LEN], int point);
static bool run()
{
int commandCount;
int order, charID, giverID, recieverID, point;
char userName[MAX_LEN], recieverName[MAX_LEN], serverName[MAX_LEN];
int ret = 0;
int ans = 0;
scanf("%d", &commandCount);
bool correct = false;
for (int tick = 0; tick < commandCount; ++tick)
{
scanf("%d", &order);
switch (order)
{
case INIT:
userInit();
correct = true;
break;
case CREATE:
scanf("%s %s %d %d", userName, serverName, &charID, &point);
if (correct)
create(tick, userName, serverName, charID, point);
break;
case DESTROY:
scanf("%d", &charID);
if (correct)
ret = destroy(tick, charID);
scanf("%d", &ans);
if (ret != ans)
correct = false;
break;
case NUMTONUM:
scanf("%d %d %d", &giverID, &recieverID, &point);
if (correct)
ret = numToNum(tick, giverID, recieverID, point);
scanf("%d", &ans);
if (ret != ans)
correct = false;
break;
case NUMTONAME:
scanf("%d %s %d", &giverID, recieverName, &point);
if (correct)
ret = numToName(tick, giverID, recieverName, point);
scanf("%d", &ans);
if (ret != ans)
correct = false;
break;
case BONUSPOINT:
scanf("%s %d", serverName, &point);
if (correct)
payBonusPoint(tick, serverName, point);
break;
}
}
return correct;
}
int main()
{
setbuf(stdout, NULL);
freopen("input.txt", "r", stdin);
int testCase, perfectScore;
scanf("%d %d", &testCase, &perfectScore);
for (int nc = 1; nc <= testCase; nc++)
{
int ncScore = run() ? perfectScore : 0;
printf("#%d %d\n", nc, ncScore);
}
return 0;
}
#endif
/////////// user code ///////////
/////////// main code ///////////