#include <iostream>
#include <vector>
#include <deque>
#include <tuple>
#include <unordered_set>
using namespace std;
struct Result
{
unsigned long Border;
unsigned long Rperimeter;
unsigned long Fperimeter;
};
// Utility class
class Task120
{
protected:
const vector<string>& Field;
const unsigned long Width;
const unsigned long Height;
protected:
unsigned int IsEnemy(int i, int j, char type)
{
if (i >=0 && i < Height && j >= 0 && j < Width) {
return (Field[i][j] != type ? 1 : 0);
}
return 0;
}
unsigned int OuterCount(int i, int j)
{
return
(unsigned int)(i == 0) +
(unsigned int)(j == 0) +
(unsigned int)(i == Height-1) +
(unsigned int)(j == Width-1);
}
public:
Task120(const vector<string>& field)
: Field(field)
, Width(field[0].size())
, Height(field.size())
{}
virtual Result solve() = 0;
};
// Простое решение за O(N^2) . Посещаем все ячейки и для каждой ячейки
// отмечаем принадлежит ли она периметру и/или линии фронта. Естественно
// учитываем сколько граней отвечают этим условиям. Дальше - простая арифметика
class Task120_Quadratic : public Task120
{
public:
Task120_Quadratic(const vector<string>& field)
: Task120(field)
{}
Result solve() override
{
unsigned long border = 0, outer = 0;
char type = Field[0][0];
for (int i = 0; i < Height; ++i) {
for (int j = 0; j < Width; ++j) {
if (Field[i][j] == type) {
outer += OuterCount(i, j);
border +=
IsEnemy(i - 1, j, Field[i][j]) +
IsEnemy(i + 1, j, Field[i][j]) +
IsEnemy(i, j - 1, Field[i][j]) +
IsEnemy(i, j + 1, Field[i][j]);
}
}
}
const auto total = 2*(Width + Height);
if (type == 'R') {
return {border, outer + border, (total - outer) + border};
} else {
return {border, (total - outer) + border , outer + border};
}
}
};
struct PairHash
{
size_t operator ()(const pair<int,int>& p) const
{
return (unsigned int)p.first * 1000 + (unsigned int)p.second;
}
};
// Чуть более сложное, но и потенциально более быстрое решение. Можно заметить, что
// если линия фронта пересекает поле от грани до грани то ее длина вполне может
// быть линейной. Во всяком случае в предыдущем решении мы просматривали точки которые
// однозначно не могли нас заинтересовать (внутренние точки областей). Было бы хорошо если
// алгоритм старался следовать границе между областями и просматривал бы только точки на линии фронта
// или точки принадлежащие только периметру. Собственно мы сдесь это и делаем. Начинаем с точки (0,0)
// т.к она точно нас интересует (принадлежит периметру) и используя очередь "интересных вершин" вдоль
// периметра и линии фронта.
// Тут есть один вырожденный случай. Это когда одна область полностью лежит внутри другой ("котел","бублик").
// Очевидно что в таком случае алгоритм не найдет линию фронта. В этом случае приходится в массиве найти первую
// точку принадлежащию противнику и повторить алгоритм в этой точке (эта точка будет граничной).
// После чего результаты скомпоновать.
// Сложность O(N^2) в худшем случае, но есть подозрение что где-то в среднем он O(n+m)
class Task120_Opt : public Task120
{
private:
unordered_set<pair<int,int>, PairHash> visited;
unsigned long border = 0, outer = 0;
private:
bool IsOutOfBounds(int i, int j) {
return
i < 0 ||
j < 0 ||
i >= Height ||
j >= Width;
}
bool IsSuitable(int i, int j, char type, unsigned int& b, unsigned int& o)
{
if (!IsOutOfBounds(i,j) && Field[i][j] == type && !visited.count(make_pair(i, j))) {
b = IsEnemy(i-1, j, Field[i][j]) +
IsEnemy(i+1, j, Field[i][j]) +
IsEnemy(i, j-1, Field[i][j]) +
IsEnemy(i, j+1, Field[i][j]);
o = OuterCount(i,j);
return true;
}
return false;
}
void TryAdd(std::deque<pair<int,int>>& q, int i, int j, char type)
{
unsigned int b = 0;
unsigned int o = 0;
if (IsSuitable(i, j, type, b, o)) {
border += b;
outer += o;
q.emplace_back(i, j);
visited.insert(make_pair(i, j));
}
}
public:
Task120_Opt(const vector<string>& field)
: Task120(field)
{}
Result RunBorderSearch(int i, int j)
{
const auto total = 2*(Width+Height);
std::deque<pair<int,int>> q;
q.emplace_back(i,j);
border += IsEnemy(i-1, j, Field[i][j]) +
IsEnemy(i+1, j, Field[i][j]) +
IsEnemy(i, j-1, Field[i][j]) +
IsEnemy(i, j+1, Field[i][j]);
outer += OuterCount(i,j);
visited.insert(make_pair(i,j));
auto type = Field[i][j];
while (!q.empty()) {
int i,j;
tie<int,int>(i,j) = q.front();
q.pop_front();
TryAdd(q, i-1, j ,type);
TryAdd(q, i+1, j, type);
TryAdd(q, i, j-1, type);
TryAdd(q, i, j+1, type);
}
if (type == 'R') {
return {border, outer + border, (total - outer) + border};
} else {
return {border, (total - outer) + border, outer + border};
}
}
Result solve()
{
auto result = RunBorderSearch(0,0);
if (result.Border == 0) {
// slow path
int ei = 0,ej = 0;
for (int i = 0; i < Field.size(); ++i) {
auto it = Field[i].find(Field[0][0] == 'F' ? 'R' : 'F');
if (it != std::string::npos) {
ei = i;
ej = (int)it;
break;
}
}
border = 0;
outer = 0;
auto result1 = RunBorderSearch(ei, ej);
return {
result1.Border,
result.Rperimeter + result1.Border,
result1.Fperimeter
};
}
return result;
}
};
int main() {
{
auto result = Task120_Quadratic({"RR","RF"}).solve();
cout << result.Border << " " << result.Rperimeter << " " << result.Fperimeter << endl;
result = Task120_Opt({"RR","RF"}).solve();
cout << result.Border << " " << result.Rperimeter << " " << result.Fperimeter << endl;
}
{
auto result = Task120_Quadratic({"RRRRRRR","RRRRRRR","RRRRRRR","RRRFRRR","RRRRRRR","RRRRRRR","RRRRRRR"}).solve();
cout << result.Border << " " << result.Rperimeter << " " << result.Fperimeter << endl;
result = Task120_Opt({"RRRRRRR","RRRRRRR","RRRRRRR","RRRFRRR","RRRRRRR","RRRRRRR","RRRRRRR"}).solve();
cout << result.Border << " " << result.Rperimeter << " " << result.Fperimeter << endl;
}
{
auto result = Task120_Quadratic({"FFFFFFF","FFFFFFF","FFFFFFF","FFFRFFF","FFFFFFF","FFFFFFF","FFFFFFF"}).solve();
cout << result.Border << " " << result.Rperimeter << " " << result.Fperimeter << endl;
result = Task120_Opt({"FFFFFFF","FFFFFFF","FFFFFFF","FFFRFFF","FFFFFFF","FFFFFFF","FFFFFFF"}).solve();
cout << result.Border << " " << result.Rperimeter << " " << result.Fperimeter << endl;
}
{
auto result = Task120_Quadratic({"FFF","FRF","FRF"}).solve();
cout << result.Border << " " << result.Rperimeter << " " << result.Fperimeter << endl;
result = Task120_Opt({"FFF","FRF","FRF"}).solve();
cout << result.Border << " " << result.Rperimeter << " " << result.Fperimeter << endl;
}
{
auto result = Task120_Quadratic({"FFF","FRF","FRF","FRF"}).solve();
cout << result.Border << " " << result.Rperimeter << " " << result.Fperimeter << endl;
result = Task120_Opt({"FFF","FRF","FRF","FRF"}).solve();
cout << result.Border << " " << result.Rperimeter << " " << result.Fperimeter << endl;
}
{
auto result = Task120_Quadratic({"FFF","FRF","FRF","FRF","FRF"}).solve();
cout << result.Border << " " << result.Rperimeter << " " << result.Fperimeter << endl;
result = Task120_Opt({"FFF","FRF","FRF","FRF","FRF"}).solve();
cout << result.Border << " " << result.Rperimeter << " " << result.Fperimeter << endl;
}
{
auto result = Task120_Quadratic({"FFFFF","FFFFF","FFFFF","FFRFF","FFRFF","FFRFF","FFRFF"}).solve();
cout << result.Border << " " << result.Rperimeter << " " << result.Fperimeter << endl;
result = Task120_Opt({"FFFFF","FFFFF","FFFFF","FFRFF","FFRFF","FFRFF","FFRFF"}).solve();
cout << result.Border << " " << result.Rperimeter << " " << result.Fperimeter << endl;
}
return 0;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8dmVjdG9yPgojaW5jbHVkZSA8ZGVxdWU+CiNpbmNsdWRlIDx0dXBsZT4KI2luY2x1ZGUgPHVub3JkZXJlZF9zZXQ+Cgp1c2luZyBuYW1lc3BhY2Ugc3RkOwoKc3RydWN0IFJlc3VsdAp7CiAgICB1bnNpZ25lZCBsb25nIEJvcmRlcjsKICAgIHVuc2lnbmVkIGxvbmcgUnBlcmltZXRlcjsKICAgIHVuc2lnbmVkIGxvbmcgRnBlcmltZXRlcjsKfTsKCi8vIFV0aWxpdHkgY2xhc3MKY2xhc3MgVGFzazEyMAp7CnByb3RlY3RlZDoKICAgIGNvbnN0IHZlY3RvcjxzdHJpbmc+JiBGaWVsZDsKICAgIGNvbnN0IHVuc2lnbmVkIGxvbmcgIFdpZHRoOwogICAgY29uc3QgdW5zaWduZWQgbG9uZyAgSGVpZ2h0OwoKcHJvdGVjdGVkOgoKICAgIHVuc2lnbmVkIGludCBJc0VuZW15KGludCBpLCBpbnQgaiwgY2hhciB0eXBlKQogICAgewogICAgICAgIGlmIChpID49MCAmJiBpIDwgSGVpZ2h0ICYmIGogPj0gMCAmJiBqIDwgV2lkdGgpIHsKICAgICAgICAgICAgcmV0dXJuIChGaWVsZFtpXVtqXSAhPSB0eXBlID8gMSA6IDApOwogICAgICAgIH0KCiAgICAgICAgcmV0dXJuIDA7CiAgICB9CgogICAgdW5zaWduZWQgaW50IE91dGVyQ291bnQoaW50IGksIGludCBqKQogICAgewogICAgICAgIHJldHVybgogICAgICAgICAgICAodW5zaWduZWQgaW50KShpID09IDApICsKICAgICAgICAgICAgKHVuc2lnbmVkIGludCkoaiA9PSAwKSArCiAgICAgICAgICAgICh1bnNpZ25lZCBpbnQpKGkgPT0gSGVpZ2h0LTEpICsKICAgICAgICAgICAgKHVuc2lnbmVkIGludCkoaiA9PSBXaWR0aC0xKTsKICAgIH0KCnB1YmxpYzoKICAgIFRhc2sxMjAoY29uc3QgdmVjdG9yPHN0cmluZz4mIGZpZWxkKQogICAgICAgIDogRmllbGQoZmllbGQpCiAgICAgICAgLCBXaWR0aChmaWVsZFswXS5zaXplKCkpCiAgICAgICAgLCBIZWlnaHQoZmllbGQuc2l6ZSgpKQogICAge30KCiAgICB2aXJ0dWFsIFJlc3VsdCBzb2x2ZSgpID0gMDsKfTsKCi8vINCf0YDQvtGB0YLQvtC1INGA0LXRiNC10L3QuNC1INC30LAgTyhOXjIpIC4g0J/QvtGB0LXRidCw0LXQvCDQstGB0LUg0Y/Rh9C10LnQutC4INC4INC00LvRjyDQutCw0LbQtNC+0Lkg0Y/Rh9C10LnQutC4Ci8vINC+0YLQvNC10YfQsNC10Lwg0L/RgNC40L3QsNC00LvQtdC20LjRgiDQu9C4INC+0L3QsCDQv9C10YDQuNC80LXRgtGA0YMg0Lgv0LjQu9C4INC70LjQvdC40Lgg0YTRgNC+0L3RgtCwLiDQldGB0YLQtdGB0YLQstC10L3QvdC+Ci8vINGD0YfQuNGC0YvQstCw0LXQvCDRgdC60L7Qu9GM0LrQviDQs9GA0LDQvdC10Lkg0L7RgtCy0LXRh9Cw0Y7RgiDRjdGC0LjQvCDRg9GB0LvQvtCy0LjRj9C8LiDQlNCw0LvRjNGI0LUgLSDQv9GA0L7RgdGC0LDRjyDQsNGA0LjRhNC80LXRgtC40LrQsApjbGFzcyBUYXNrMTIwX1F1YWRyYXRpYyA6IHB1YmxpYyBUYXNrMTIwCnsKcHVibGljOgogICAgVGFzazEyMF9RdWFkcmF0aWMoY29uc3QgdmVjdG9yPHN0cmluZz4mIGZpZWxkKQogICAgICAgIDogVGFzazEyMChmaWVsZCkKICAgIHt9CgogICAgUmVzdWx0IHNvbHZlKCkgb3ZlcnJpZGUKICAgIHsKICAgICAgICB1bnNpZ25lZCBsb25nICBib3JkZXIgPSAwLCBvdXRlciA9IDA7CiAgICAgICAgY2hhciB0eXBlID0gRmllbGRbMF1bMF07CgogICAgICAgIGZvciAoaW50IGkgPSAwOyBpIDwgSGVpZ2h0OyArK2kpIHsKICAgICAgICAgICAgZm9yIChpbnQgaiA9IDA7IGogPCBXaWR0aDsgKytqKSB7CiAgICAgICAgICAgICAgICBpZiAoRmllbGRbaV1bal0gPT0gdHlwZSkgewogICAgICAgICAgICAgICAgICAgIG91dGVyICs9IE91dGVyQ291bnQoaSwgaik7CiAgICAgICAgICAgICAgICAgICAgYm9yZGVyICs9CiAgICAgICAgICAgICAgICAgICAgICAgIElzRW5lbXkoaSAtIDEsIGosIEZpZWxkW2ldW2pdKSArCiAgICAgICAgICAgICAgICAgICAgICAgIElzRW5lbXkoaSArIDEsIGosIEZpZWxkW2ldW2pdKSArCiAgICAgICAgICAgICAgICAgICAgICAgIElzRW5lbXkoaSwgaiAtIDEsIEZpZWxkW2ldW2pdKSArCiAgICAgICAgICAgICAgICAgICAgICAgIElzRW5lbXkoaSwgaiArIDEsIEZpZWxkW2ldW2pdKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgY29uc3QgYXV0byB0b3RhbCA9IDIqKFdpZHRoICsgSGVpZ2h0KTsKCiAgICAgICAgaWYgKHR5cGUgPT0gJ1InKSB7CiAgICAgICAgICAgIHJldHVybiB7Ym9yZGVyLCBvdXRlciArIGJvcmRlciwgKHRvdGFsIC0gb3V0ZXIpICsgYm9yZGVyfTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgICByZXR1cm4ge2JvcmRlciwgKHRvdGFsIC0gb3V0ZXIpICsgYm9yZGVyICwgb3V0ZXIgKyBib3JkZXJ9OwogICAgICAgIH0KCiAgICB9Cn07CgoKc3RydWN0IFBhaXJIYXNoCnsKICAgIHNpemVfdCBvcGVyYXRvciAoKShjb25zdCBwYWlyPGludCxpbnQ+JiBwKSBjb25zdAogICAgewogICAgICAgIHJldHVybiAodW5zaWduZWQgaW50KXAuZmlyc3QgKiAxMDAwICsgKHVuc2lnbmVkIGludClwLnNlY29uZDsKICAgIH0KfTsKCi8vINCn0YPRgtGMINCx0L7Qu9C10LUg0YHQu9C+0LbQvdC+0LUsINC90L4g0Lgg0L/QvtGC0LXQvdGG0LjQsNC70YzQvdC+INCx0L7Qu9C10LUg0LHRi9GB0YLRgNC+0LUg0YDQtdGI0LXQvdC40LUuINCc0L7QttC90L4g0LfQsNC80LXRgtC40YLRjCwg0YfRgtC+Ci8vINC10YHQu9C4INC70LjQvdC40Y8g0YTRgNC+0L3RgtCwINC/0LXRgNC10YHQtdC60LDQtdGCINC/0L7Qu9C1INC+0YIg0LPRgNCw0L3QuCDQtNC+INCz0YDQsNC90Lgg0YLQviDQtdC1INC00LvQuNC90LAg0LLQv9C+0LvQvdC1INC80L7QttC10YIKLy8g0LHRi9GC0Ywg0LvQuNC90LXQudC90L7QuS4g0JLQviDQstGB0Y/QutC+0Lwg0YHQu9GD0YfQsNC1INCyINC/0YDQtdC00YvQtNGD0YnQtdC8INGA0LXRiNC10L3QuNC4INC80Ysg0L/RgNC+0YHQvNCw0YLRgNC40LLQsNC70Lgg0YLQvtGH0LrQuCDQutC+0YLQvtGA0YvQtQovLyDQvtC00L3QvtC30L3QsNGH0L3QviDQvdC1INC80L7Qs9C70Lgg0L3QsNGBINC30LDQuNC90YLQtdGA0LXRgdC+0LLQsNGC0YwgKNCy0L3Rg9GC0YDQtdC90L3QuNC1INGC0L7Rh9C60Lgg0L7QsdC70LDRgdGC0LXQuSkuINCR0YvQu9C+INCx0Ysg0YXQvtGA0L7RiNC+INC10YHQu9C4Ci8vINCw0LvQs9C+0YDQuNGC0Lwg0YHRgtCw0YDQsNC70YHRjyDRgdC70LXQtNC+0LLQsNGC0Ywg0LPRgNCw0L3QuNGG0LUg0LzQtdC20LTRgyDQvtCx0LvQsNGB0YLRj9C80Lgg0Lgg0L/RgNC+0YHQvNCw0YLRgNC40LLQsNC7INCx0Ysg0YLQvtC70YzQutC+INGC0L7Rh9C60Lgg0L3QsCDQu9C40L3QuNC4INGE0YDQvtC90YLQsAovLyDQuNC70Lgg0YLQvtGH0LrQuCDQv9GA0LjQvdCw0LTQu9C10LbQsNGJ0LjQtSDRgtC+0LvRjNC60L4g0L/QtdGA0LjQvNC10YLRgNGDLiDQodC+0LHRgdGC0LLQtdC90L3QviDQvNGLINGB0LTQtdGB0Ywg0Y3RgtC+INC4INC00LXQu9Cw0LXQvC4g0J3QsNGH0LjQvdCw0LXQvCDRgSDRgtC+0YfQutC4ICgwLDApCi8vINGCLtC6INC+0L3QsCDRgtC+0YfQvdC+INC90LDRgSDQuNC90YLQtdGA0LXRgdGD0LXRgiAo0L/RgNC40L3QsNC00LvQtdC20LjRgiDQv9C10YDQuNC80LXRgtGA0YMpINC4INC40YHQv9C+0LvRjNC30YPRjyDQvtGH0LXRgNC10LTRjCAi0LjQvdGC0LXRgNC10YHQvdGL0YUg0LLQtdGA0YjQuNC9IiDQstC00L7Qu9GMCi8vINC/0LXRgNC40LzQtdGC0YDQsCDQuCDQu9C40L3QuNC4INGE0YDQvtC90YLQsC4KLy8g0KLRg9GCINC10YHRgtGMINC+0LTQuNC9INCy0YvRgNC+0LbQtNC10L3QvdGL0Lkg0YHQu9GD0YfQsNC5LiDQrdGC0L4g0LrQvtCz0LTQsCDQvtC00L3QsCDQvtCx0LvQsNGB0YLRjCDQv9C+0LvQvdC+0YHRgtGM0Y4g0LvQtdC20LjRgiDQstC90YPRgtGA0Lgg0LTRgNGD0LPQvtC5ICgi0LrQvtGC0LXQuyIsItCx0YPQsdC70LjQuiIpLgovLyDQntGH0LXQstC40LTQvdC+INGH0YLQviDQsiDRgtCw0LrQvtC8INGB0LvRg9GH0LDQtSDQsNC70LPQvtGA0LjRgtC8INC90LUg0L3QsNC50LTQtdGCINC70LjQvdC40Y4g0YTRgNC+0L3RgtCwLiDQkiDRjdGC0L7QvCDRgdC70YPRh9Cw0LUg0L/RgNC40YXQvtC00LjRgtGB0Y8g0LIg0LzQsNGB0YHQuNCy0LUg0L3QsNC50YLQuCDQv9C10YDQstGD0Y4KLy8g0YLQvtGH0LrRgyDQv9GA0LjQvdCw0LTQu9C10LbQsNGJ0LjRjiDQv9GA0L7RgtC40LLQvdC40LrRgyDQuCDQv9C+0LLRgtC+0YDQuNGC0Ywg0LDQu9Cz0L7RgNC40YLQvCDQsiDRjdGC0L7QuSDRgtC+0YfQutC1ICjRjdGC0LAg0YLQvtGH0LrQsCDQsdGD0LTQtdGCINCz0YDQsNC90LjRh9C90L7QuSkuCi8vINCf0L7RgdC70LUg0YfQtdCz0L4g0YDQtdC30YPQu9GM0YLQsNGC0Ysg0YHQutC+0LzQv9C+0L3QvtCy0LDRgtGMLgovLyDQodC70L7QttC90L7RgdGC0YwgTyhOXjIpINCyINGF0YPQtNGI0LXQvCDRgdC70YPRh9Cw0LUsINC90L4g0LXRgdGC0Ywg0L/QvtC00L7Qt9GA0LXQvdC40LUg0YfRgtC+INCz0LTQtS3RgtC+INCyINGB0YDQtdC00L3QtdC8INC+0L0gTyhuK20pCgpjbGFzcyBUYXNrMTIwX09wdCA6IHB1YmxpYyBUYXNrMTIwCnsKcHJpdmF0ZToKICAgIHVub3JkZXJlZF9zZXQ8cGFpcjxpbnQsaW50PiwgUGFpckhhc2g+IHZpc2l0ZWQ7CiAgICB1bnNpZ25lZCBsb25nICBib3JkZXIgPSAwLCBvdXRlciA9IDA7Cgpwcml2YXRlOgoKICAgIGJvb2wgSXNPdXRPZkJvdW5kcyhpbnQgaSwgaW50IGopIHsKICAgICAgICByZXR1cm4KICAgICAgICBpIDwgMCB8fAogICAgICAgIGogPCAwIHx8CiAgICAgICAgaSA+PSBIZWlnaHQgfHwKICAgICAgICBqID49IFdpZHRoOwogICAgfQoKICAgIGJvb2wgSXNTdWl0YWJsZShpbnQgaSwgaW50IGosIGNoYXIgdHlwZSwgdW5zaWduZWQgaW50JiBiLCB1bnNpZ25lZCBpbnQmIG8pCiAgICB7CiAgICAgICAgaWYgKCFJc091dE9mQm91bmRzKGksaikgJiYgRmllbGRbaV1bal0gPT0gdHlwZSAmJiAhdmlzaXRlZC5jb3VudChtYWtlX3BhaXIoaSwgaikpKSB7CiAgICAgICAgICAgIGIgPSBJc0VuZW15KGktMSwgaiwgRmllbGRbaV1bal0pICsKICAgICAgICAgICAgICAgICAgICAgICAgICBJc0VuZW15KGkrMSwgaiwgRmllbGRbaV1bal0pICsKICAgICAgICAgICAgICAgICAgICAgICAgICBJc0VuZW15KGksIGotMSwgRmllbGRbaV1bal0pICsKICAgICAgICAgICAgICAgICAgICAgICAgICBJc0VuZW15KGksIGorMSwgRmllbGRbaV1bal0pOwogICAgICAgICAgICBvID0gIE91dGVyQ291bnQoaSxqKTsKCiAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgIH0KICAgICAgICByZXR1cm4gZmFsc2U7CiAgICB9CgogICAgdm9pZCBUcnlBZGQoc3RkOjpkZXF1ZTxwYWlyPGludCxpbnQ+PiYgcSwgaW50IGksIGludCBqLCBjaGFyIHR5cGUpCiAgICB7CiAgICAgICAgdW5zaWduZWQgaW50IGIgPSAwOwogICAgICAgIHVuc2lnbmVkIGludCBvID0gMDsKICAgICAgICBpZiAoSXNTdWl0YWJsZShpLCBqLCB0eXBlLCBiLCBvKSkgewogICAgICAgICAgICBib3JkZXIgKz0gYjsKICAgICAgICAgICAgb3V0ZXIgKz0gbzsKICAgICAgICAgICAgcS5lbXBsYWNlX2JhY2soaSwgaik7CiAgICAgICAgICAgIHZpc2l0ZWQuaW5zZXJ0KG1ha2VfcGFpcihpLCBqKSk7CiAgICAgICAgfQogICAgfQoKcHVibGljOgogICAgVGFzazEyMF9PcHQoY29uc3QgdmVjdG9yPHN0cmluZz4mIGZpZWxkKQogICAgICAgIDogVGFzazEyMChmaWVsZCkKICAgIHt9CgoKICAgIFJlc3VsdCBSdW5Cb3JkZXJTZWFyY2goaW50IGksIGludCBqKQogICAgewogICAgICAgIGNvbnN0IGF1dG8gdG90YWwgPSAyKihXaWR0aCtIZWlnaHQpOwoKICAgICAgICBzdGQ6OmRlcXVlPHBhaXI8aW50LGludD4+IHE7CgogICAgICAgIHEuZW1wbGFjZV9iYWNrKGksaik7CgogICAgICAgIGJvcmRlciArPSBJc0VuZW15KGktMSwgaiwgRmllbGRbaV1bal0pICsKICAgICAgICAgICAgICAgICAgSXNFbmVteShpKzEsIGosIEZpZWxkW2ldW2pdKSArCiAgICAgICAgICAgICAgICAgIElzRW5lbXkoaSwgai0xLCBGaWVsZFtpXVtqXSkgKwogICAgICAgICAgICAgICAgICBJc0VuZW15KGksIGorMSwgRmllbGRbaV1bal0pOwoKICAgICAgICBvdXRlciArPSAgT3V0ZXJDb3VudChpLGopOwoKICAgICAgICB2aXNpdGVkLmluc2VydChtYWtlX3BhaXIoaSxqKSk7CgogICAgICAgIGF1dG8gdHlwZSA9IEZpZWxkW2ldW2pdOwoKICAgICAgICB3aGlsZSAoIXEuZW1wdHkoKSkgewogICAgICAgICAgICBpbnQgaSxqOwogICAgICAgICAgICB0aWU8aW50LGludD4oaSxqKSA9IHEuZnJvbnQoKTsKICAgICAgICAgICAgcS5wb3BfZnJvbnQoKTsKCiAgICAgICAgICAgIFRyeUFkZChxLCBpLTEsIGogLHR5cGUpOwogICAgICAgICAgICBUcnlBZGQocSwgaSsxLCBqLCB0eXBlKTsKICAgICAgICAgICAgVHJ5QWRkKHEsIGksIGotMSwgdHlwZSk7CiAgICAgICAgICAgIFRyeUFkZChxLCBpLCBqKzEsIHR5cGUpOwogICAgICAgIH0KCiAgICAgICAgaWYgKHR5cGUgPT0gJ1InKSB7CiAgICAgICAgICAgIHJldHVybiB7Ym9yZGVyLCBvdXRlciArIGJvcmRlciwgKHRvdGFsIC0gb3V0ZXIpICsgYm9yZGVyfTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgICByZXR1cm4ge2JvcmRlciwgKHRvdGFsIC0gb3V0ZXIpICsgYm9yZGVyLCBvdXRlciArIGJvcmRlcn07CiAgICAgICAgfQogICAgfQoKICAgIFJlc3VsdCBzb2x2ZSgpCiAgICB7CiAgICAgICAgYXV0byByZXN1bHQgPSBSdW5Cb3JkZXJTZWFyY2goMCwwKTsKCiAgICAgICAgaWYgKHJlc3VsdC5Cb3JkZXIgPT0gMCkgewogICAgICAgICAgICAvLyBzbG93IHBhdGgKCiAgICAgICAgICAgIGludCBlaSA9IDAsZWogPSAwOwoKICAgICAgICAgICAgZm9yIChpbnQgaSA9IDA7IGkgPCBGaWVsZC5zaXplKCk7ICsraSkgewogICAgICAgICAgICAgICAgYXV0byBpdCA9IEZpZWxkW2ldLmZpbmQoRmllbGRbMF1bMF0gPT0gJ0YnID8gJ1InIDogJ0YnKTsKICAgICAgICAgICAgICAgIGlmIChpdCAhPSBzdGQ6OnN0cmluZzo6bnBvcykgewogICAgICAgICAgICAgICAgICAgIGVpID0gaTsKICAgICAgICAgICAgICAgICAgICBlaiA9IChpbnQpaXQ7CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGJvcmRlciA9IDA7CiAgICAgICAgICAgIG91dGVyID0gMDsKCiAgICAgICAgICAgIGF1dG8gcmVzdWx0MSA9IFJ1bkJvcmRlclNlYXJjaChlaSwgZWopOwoKICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICAgIHJlc3VsdDEuQm9yZGVyLAogICAgICAgICAgICAgICAgcmVzdWx0LlJwZXJpbWV0ZXIgKyByZXN1bHQxLkJvcmRlciwKICAgICAgICAgICAgICAgIHJlc3VsdDEuRnBlcmltZXRlcgogICAgICAgICAgICAgICAgfTsKICAgICAgICB9CgogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICB9Cn07CgppbnQgbWFpbigpIHsKCiAgICB7CiAgICAgICAgYXV0byByZXN1bHQgPSBUYXNrMTIwX1F1YWRyYXRpYyh7IlJSIiwiUkYifSkuc29sdmUoKTsKICAgICAgICBjb3V0IDw8IHJlc3VsdC5Cb3JkZXIgPDwgIiAiIDw8IHJlc3VsdC5ScGVyaW1ldGVyIDw8ICIgIiA8PCByZXN1bHQuRnBlcmltZXRlciA8PCBlbmRsOwogICAgICAgIHJlc3VsdCA9IFRhc2sxMjBfT3B0KHsiUlIiLCJSRiJ9KS5zb2x2ZSgpOwogICAgICAgIGNvdXQgPDwgcmVzdWx0LkJvcmRlciA8PCAiICIgPDwgcmVzdWx0LlJwZXJpbWV0ZXIgPDwgIiAiIDw8IHJlc3VsdC5GcGVyaW1ldGVyIDw8IGVuZGw7CiAgICB9CgogICAgewogICAgICAgIGF1dG8gcmVzdWx0ID0gVGFzazEyMF9RdWFkcmF0aWMoeyJSUlJSUlJSIiwiUlJSUlJSUiIsIlJSUlJSUlIiLCJSUlJGUlJSIiwiUlJSUlJSUiIsIlJSUlJSUlIiLCJSUlJSUlJSIn0pLnNvbHZlKCk7CiAgICAgICAgY291dCA8PCByZXN1bHQuQm9yZGVyIDw8ICIgIiA8PCByZXN1bHQuUnBlcmltZXRlciA8PCAiICIgPDwgcmVzdWx0LkZwZXJpbWV0ZXIgPDwgZW5kbDsKICAgICAgICByZXN1bHQgPSBUYXNrMTIwX09wdCh7IlJSUlJSUlIiLCJSUlJSUlJSIiwiUlJSUlJSUiIsIlJSUkZSUlIiLCJSUlJSUlJSIiwiUlJSUlJSUiIsIlJSUlJSUlIifSkuc29sdmUoKTsKICAgICAgICBjb3V0IDw8IHJlc3VsdC5Cb3JkZXIgPDwgIiAiIDw8IHJlc3VsdC5ScGVyaW1ldGVyIDw8ICIgIiA8PCByZXN1bHQuRnBlcmltZXRlciA8PCBlbmRsOwogICAgfQoKICAgIHsKICAgICAgICBhdXRvIHJlc3VsdCA9IFRhc2sxMjBfUXVhZHJhdGljKHsiRkZGRkZGRiIsIkZGRkZGRkYiLCJGRkZGRkZGIiwiRkZGUkZGRiIsIkZGRkZGRkYiLCJGRkZGRkZGIiwiRkZGRkZGRiJ9KS5zb2x2ZSgpOwogICAgICAgIGNvdXQgPDwgcmVzdWx0LkJvcmRlciA8PCAiICIgPDwgcmVzdWx0LlJwZXJpbWV0ZXIgPDwgIiAiIDw8IHJlc3VsdC5GcGVyaW1ldGVyIDw8IGVuZGw7CiAgICAgICAgcmVzdWx0ID0gVGFzazEyMF9PcHQoeyJGRkZGRkZGIiwiRkZGRkZGRiIsIkZGRkZGRkYiLCJGRkZSRkZGIiwiRkZGRkZGRiIsIkZGRkZGRkYiLCJGRkZGRkZGIn0pLnNvbHZlKCk7CiAgICAgICAgY291dCA8PCByZXN1bHQuQm9yZGVyIDw8ICIgIiA8PCByZXN1bHQuUnBlcmltZXRlciA8PCAiICIgPDwgcmVzdWx0LkZwZXJpbWV0ZXIgPDwgZW5kbDsKICAgIH0KCiAgICB7CiAgICAgICAgYXV0byByZXN1bHQgPSBUYXNrMTIwX1F1YWRyYXRpYyh7IkZGRiIsIkZSRiIsIkZSRiJ9KS5zb2x2ZSgpOwogICAgICAgIGNvdXQgPDwgcmVzdWx0LkJvcmRlciA8PCAiICIgPDwgcmVzdWx0LlJwZXJpbWV0ZXIgPDwgIiAiIDw8IHJlc3VsdC5GcGVyaW1ldGVyIDw8IGVuZGw7CiAgICAgICAgcmVzdWx0ID0gVGFzazEyMF9PcHQoeyJGRkYiLCJGUkYiLCJGUkYifSkuc29sdmUoKTsKICAgICAgICBjb3V0IDw8IHJlc3VsdC5Cb3JkZXIgPDwgIiAiIDw8IHJlc3VsdC5ScGVyaW1ldGVyIDw8ICIgIiA8PCByZXN1bHQuRnBlcmltZXRlciA8PCBlbmRsOwogICAgfQoKICAgIHsKICAgICAgICBhdXRvIHJlc3VsdCA9IFRhc2sxMjBfUXVhZHJhdGljKHsiRkZGIiwiRlJGIiwiRlJGIiwiRlJGIn0pLnNvbHZlKCk7CiAgICAgICAgY291dCA8PCByZXN1bHQuQm9yZGVyIDw8ICIgIiA8PCByZXN1bHQuUnBlcmltZXRlciA8PCAiICIgPDwgcmVzdWx0LkZwZXJpbWV0ZXIgPDwgZW5kbDsKICAgICAgICByZXN1bHQgPSBUYXNrMTIwX09wdCh7IkZGRiIsIkZSRiIsIkZSRiIsIkZSRiJ9KS5zb2x2ZSgpOwogICAgICAgIGNvdXQgPDwgcmVzdWx0LkJvcmRlciA8PCAiICIgPDwgcmVzdWx0LlJwZXJpbWV0ZXIgPDwgIiAiIDw8IHJlc3VsdC5GcGVyaW1ldGVyIDw8IGVuZGw7CiAgICB9CgogICAgewogICAgICAgIGF1dG8gcmVzdWx0ID0gVGFzazEyMF9RdWFkcmF0aWMoeyJGRkYiLCJGUkYiLCJGUkYiLCJGUkYiLCJGUkYifSkuc29sdmUoKTsKICAgICAgICBjb3V0IDw8IHJlc3VsdC5Cb3JkZXIgPDwgIiAiIDw8IHJlc3VsdC5ScGVyaW1ldGVyIDw8ICIgIiA8PCByZXN1bHQuRnBlcmltZXRlciA8PCBlbmRsOwogICAgICAgIHJlc3VsdCA9IFRhc2sxMjBfT3B0KHsiRkZGIiwiRlJGIiwiRlJGIiwiRlJGIiwiRlJGIn0pLnNvbHZlKCk7CiAgICAgICAgY291dCA8PCByZXN1bHQuQm9yZGVyIDw8ICIgIiA8PCByZXN1bHQuUnBlcmltZXRlciA8PCAiICIgPDwgcmVzdWx0LkZwZXJpbWV0ZXIgPDwgZW5kbDsKICAgIH0KCiAgICB7CiAgICAgICAgYXV0byByZXN1bHQgPSBUYXNrMTIwX1F1YWRyYXRpYyh7IkZGRkZGIiwiRkZGRkYiLCJGRkZGRiIsIkZGUkZGIiwiRkZSRkYiLCJGRlJGRiIsIkZGUkZGIn0pLnNvbHZlKCk7CiAgICAgICAgY291dCA8PCByZXN1bHQuQm9yZGVyIDw8ICIgIiA8PCByZXN1bHQuUnBlcmltZXRlciA8PCAiICIgPDwgcmVzdWx0LkZwZXJpbWV0ZXIgPDwgZW5kbDsKICAgICAgICByZXN1bHQgPSBUYXNrMTIwX09wdCh7IkZGRkZGIiwiRkZGRkYiLCJGRkZGRiIsIkZGUkZGIiwiRkZSRkYiLCJGRlJGRiIsIkZGUkZGIn0pLnNvbHZlKCk7CiAgICAgICAgY291dCA8PCByZXN1bHQuQm9yZGVyIDw8ICIgIiA8PCByZXN1bHQuUnBlcmltZXRlciA8PCAiICIgPDwgcmVzdWx0LkZwZXJpbWV0ZXIgPDwgZW5kbDsKICAgIH0KCgogICAgcmV0dXJuIDA7Cn0=