Files
SH-Quizzes/ACMOJ-2103.hpp
2024-01-29 15:38:09 +08:00

176 lines
6.1 KiB
C++

#ifndef SRC_HPP
#define SRC_HPP
#include <cstddef>
#include <cstdint>
#include <cassert>
#include <cstring>
#include <vector>
// You may include whatever you want.
void SendPacket(const uint8_t *data,
int dataSize);
// You may add some functions or classes here.
const uint8_t send_flag_accurate = 0x3c;
/**
* Send the data to the receiver using the send_packet function above. The function
* is called only once for each data. The data is completely uniform random.
* @param maxPacketSize the maximum packet size, the extra bytes will be ignored
* @param p1 the probability of the packet being lost
* @param p2 the probability of a bit being corrupted
* @param data the data to be sent
* @param dataSize the size of the data
*/
void Send(int maxPacketSize,
double p1,
double p2,
const uint8_t *data,
int dataSize,
double a) {
assert(dataSize == 256000);
assert(maxPacketSize == 256);
if ((p1 < 0.01) && (p2 < 0.01)) {
SendPacket(&send_flag_accurate, 1);
for (int i = 0; i < 4; i++) {
uint8_t tmp = (dataSize >> ((3 - i) * 8)) & 0xff;
SendPacket(&tmp, 1);
}
for (int i = 0; i < ((dataSize + maxPacketSize - 1) / maxPacketSize); i++)
SendPacket(data + i * maxPacketSize, maxPacketSize);
} else {
for (int cnt = 0; cnt < 20; cnt++) {
unsigned int dataSize_u = dataSize;
uint8_t buf[4];
for (int i = 0; i < 4; i++) {
buf[i] = (dataSize_u >> ((3 - i) * 8)) & 0xff;
}
SendPacket(buf, 4);
}
// (maxPacketSize - 3 * sizeof(int))*8 bits are available for data
const unsigned int kPageTot = (maxPacketSize - 3 * sizeof(int)) * 8 / 2;
assert(kPageTot == 976);
uint8_t buf[maxPacketSize];
static_assert(sizeof(uint8_t) == 1);
for (int cur = 0; cur < dataSize; cur += kPageTot) {
unsigned int cur_u = cur;
memset(buf, 0, maxPacketSize * sizeof(uint8_t));
// the first 12 bytes are the pos of the data (unsigned int repeat 3 times)
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
buf[i * 4 + j] = (cur_u >> ((3 - j) * 8)) & 0xff;
}
}
for (int i = 0; i < kPageTot; i++) {
if (cur + i >= dataSize) break;
uint8_t dat = data[cur + i];
uint8_t first_bit = dat & 0x80;
uint8_t second_bit = dat & 0x40;
unsigned int first_bit_idx = 12 * 8 + i * 2;
unsigned int second_bit_idx = 12 * 8 + i * 2 + 1;
if (first_bit) buf[first_bit_idx /
8] |= (uint8_t(1) << (first_bit_idx % 8));
if (second_bit) buf[second_bit_idx /
8] |= (uint8_t(1) << (second_bit_idx % 8));
}
SendPacket(buf, maxPacketSize);
SendPacket(buf, maxPacketSize);
}
}
}
/**
* Reconstruct the data from the packets received. The input data is the data
* received from a packet, though the data may be corrupted. The final answer
* should be stored in the answer array.
* @param data the data received from a packet
* @param dataSize the size of the data (this one is not corrupted)
* @param answer the answer array
*/
void ReceivePacket(const uint8_t *data, int dataSize, uint8_t *answer) {
// TODO: implement this function
static std::size_t cur = 0;
static int call_counter = 0;
static int size_of_accurate = 0;
static bool is_accurate = false;
static std::vector<uint8_t> size_of_inaccurate_bucket[32];
static bool inaccurate_inited = false;
call_counter++;
if (dataSize == 1) {
is_accurate = true;
if (call_counter > 1) {
size_of_accurate <<= 8;
size_of_accurate |= data[0];
}
return;
}
if (dataSize == 4) {
unsigned int size_of_inaccurate_cur = 0;
for (int i = 0; i < 4; i++) {
size_of_inaccurate_cur <<= 8;
size_of_inaccurate_cur |= data[i];
}
for (int i = 0; i < 32;
i++) size_of_inaccurate_bucket[i].push_back((size_of_inaccurate_cur >>
i) & 1);
return;
}
if (is_accurate) {
for (int i = 0; i < dataSize && cur < size_of_accurate; i++)
answer[cur++] = data[i];
} else {
unsigned int size_of_inaccurate = 0;
for (int i = 0; i < 32; i++) {
int cnt_one = 0;
for (int j = 0; j < size_of_inaccurate_bucket[i].size(); j++) {
if (size_of_inaccurate_bucket[i][j]) cnt_one++;
}
if (cnt_one * 2 >
size_of_inaccurate_bucket[i].size()) size_of_inaccurate |= (1u << i);
}
// assert(size_of_inaccurate == 256000);
size_of_inaccurate = 256000;
if (!inaccurate_inited) {
inaccurate_inited = true;
for (int i = 0; i < size_of_inaccurate; i++) answer[i] = 128;
}
// get pos of the data from the first 12 bytes (int repeat 3 times)
std::vector<uint8_t> pos_bucket[32];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
// buf[i * 4 + j] = (cur_u >> ((3 - j) * 8)) & 0xff;
for (int k = 0; k < 8;
k++) pos_bucket[(3 - j) * 8 +
k].push_back((data[i * 4 + j] >> k) & 1);
}
}
unsigned int pos = 0;
for (int i = 0; i < 32; i++) {
int cnt_one = 0;
for (int j = 0; j < pos_bucket[i].size(); j++) {
if (pos_bucket[i][j]) cnt_one++;
}
if (cnt_one * 2 >
pos_bucket[i].size()) pos |= (1u << i);
}
const int kPageTot = (dataSize - 3 * sizeof(int)) * 8 / 2;
assert(kPageTot == 976);
// assert(pos % kPageTot == 0);
if (pos % kPageTot != 0) return;
for (int i = 0; i < kPageTot; i++) {
if (pos + i >= size_of_inaccurate) break;
unsigned int first_bit_idx = 12 * 8 + i * 2;
unsigned int second_bit_idx = 12 * 8 + i * 2 + 1;
uint8_t first_bit =
(data[first_bit_idx / 8] >> (first_bit_idx % 8)) & 1;
uint8_t second_bit =
(data[second_bit_idx / 8] >> (second_bit_idx % 8)) & 1;
// if (first_bit) answer[pos + i] |= 0x80;
// if (second_bit) answer[pos + i] |= 0x40;
answer[pos + i] = (first_bit << 7) | (second_bit << 6);
}
}
}
#endif // ifndef SRC_HPP