比賽位址
弱校連萌寒假專題一
題解前繼
2015弱校連萌寒假專題一 題解(A-J)
K. Alignment of Code
題意:
給定n行文章,每行是由空格分隔的一些單詞,請你适當地增删空格,使得每一列的單詞在每一行的開始位置相同,且每一列最長的單詞和它後面的單詞隻有一個空格分隔。
n <= 1000, 單詞長度 <= 80, 一行文章長度 <= 180。
題解:
讀入n行文章之後計算每列最長單詞長度,按要求輸出即可。注意不能有多餘的行末空格。時間複雜度O(字元數)。
代碼:
#include <cstdio>
#include <cstring>
const int maxn = 1010, maxl = 200;
int t, n, cnt[maxn], sta[maxn][maxl], end[maxn][maxl], maxlen[maxl];
char str[maxn][maxl];
int max(int x, int y)
{
return x < y ? y : x;
}
int main()
{
scanf("%d\n", &t);
while(t--)
{
memset(cnt, 0, sizeof cnt);
memset(maxlen, 0, sizeof maxlen);
for(n = 0; gets(str[n]) != NULL; ++n)
if(str[n][0] == '@' && str[n][1] == '\0')
break;
for(int i = 0; i < n; ++i)
{
for(int j = 0, k = 0; str[i][j]; j = k)
{
while(str[i][j] == ' ')
++j;
k = j;
while(str[i][k] && str[i][k] != ' ')
++k;
if(j < k)
{
sta[i][cnt[i]] = j;
end[i][cnt[i]] = k;
maxlen[cnt[i]] = max(maxlen[cnt[i]], k - j);
++cnt[i];
}
}
}
for(int i = 0; i < n; ++i)
{
for(int j = 0; j < cnt[i]; ++j)
{
if(j)
putchar(' ');
str[i][end[i][j]] = '\0';
if(j + 1 == cnt[i])
printf("%s", str[i] + sta[i][j]);
else
printf("%-*s", maxlen[j], str[i] + sta[i][j]);
}
putchar('\n');
}
}
return 0;
}
L. Ducci Sequence
題意:
給定長度為n的數列{a_n},每次将{a_1, a_2, ..., a_n}變成{|a_1 - a_2|, |a_2 - a_3|, ..., |a_n - a_1|},問這樣的操作是否會變成{0, 0, ..., 0},還是會一直循環下去。
n <= 15, 若有循環節則一定在1000步操作内出現。
題解:
直接模拟前1000次操作,每次檢查目前數列是否出現過,利用Hash可以做到時間複雜度O(kn),k >= 1000。
代碼:
#include <map>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 16;
int n;
struct DucciSeq
{
int a[maxn];
bool operator < (const DucciSeq &x) const
{
for(int i = 0; i < maxn; ++i)
if(a[i] != x.a[i])
return a[i] < x.a[i];
return 0;
}
bool empty() const
{
for(int i = 0; i < n; ++i)
if(a[i])
return 0;
return 1;
}
} x;
map<DucciSeq, int> Hash;
int abs(int x)
{
return x < 0 ? -x : x;
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
memset(&x, 0, sizeof x);
Hash.clear();
scanf("%d", &n);
for(int i = 0; i < n; ++i)
scanf("%d", &x.a[i]);
if(x.empty())
{
puts("ZERO");
continue;
}
Hash[x] = 1;
for(int t = 1; t <= 1000; ++t)
{
int tmp = x.a[0];
for(int i = 0; i < n - 1; ++i)
x.a[i] = abs(x.a[i] - x.a[i + 1]);
x.a[n - 1] = abs(x.a[n - 1] - tmp);
if(x.empty())
{
puts("ZERO");
break;
}
else if(Hash[x])
{
puts("LOOP");
break;
}
Hash[x] = 1;
}
}
return 0;
}
M. The Letter Carrier's Rounds
題意:
給定SMTP的工作方式,模拟MTA發送方的SMTP操作,包括MTA接收方的回饋資訊。
題解:
記錄每個MTA的使用者名便于快速查找,然後按照題意模拟即可。
代碼:
#include <map>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
typedef map<string, int> Users;
map<string, Users> MTA;
string sender, text;
map<string, int> idx, vis;
vector<vector<string> > recver;
int main()
{
ios::sync_with_stdio(0);
while(cin >> text && text != "*")
{
int cnt;
Users tmp;
tmp.clear();
cin >> text >> cnt;
while(cnt--)
{
cin >> sender;
tmp[sender] = 1;
}
MTA[text] = tmp;
}
while(cin >> sender && sender != "*")
{
int cnt = 0;
string::size_type pos = sender.find('@');
string senderMTA = sender.substr(pos + 1), recverMTA, tmp;
idx.clear();
vis.clear();
for(vector<vector<string> >::iterator it = recver.begin(), jt = recver.end(); it < jt; ++it)
(*it).clear();
recver.clear();
while(cin >> tmp && tmp != "*")
{
recverMTA = tmp.substr(tmp.find('@') + 1);
if(vis.find(tmp) != vis.end())
continue;
vis[tmp] = 1;
if(idx.find(recverMTA) == idx.end())
{
idx[recverMTA] = cnt++;
vector<string> name;
name.clear();
name.push_back(tmp);
recver.push_back(name);
}
else
recver[idx[recverMTA]].push_back(tmp);
}
text = "";
getline(cin, tmp);
while(getline(cin, tmp) && tmp != "*")
text += " " + tmp + "\n";
Users List = MTA[senderMTA];
if(List.find(sender.substr(0, sender.find('@'))) == List.end())
continue;
for(vector<vector<string> >::iterator it = recver.begin(), jt = recver.end(); it < jt; ++it)
{
vector<string> &temp = *it;
recverMTA = temp[0].substr(temp[0].find('@') + 1);
List = MTA[recverMTA];
cout << "Connection between " + senderMTA + " and " + recverMTA << endl;
cout << " HELO " + senderMTA << endl;
cout << " 250" << endl;
cout << " MAIL FROM:<" + sender + ">" << endl;
cout << " 250" << endl;
bool flag = 0;
for(vector<string>::iterator it = temp.begin(), jt = temp.end(); it < jt; ++it)
{
cout << " RCPT TO:<" + *it + ">" << endl;
if(List.find((*it).substr(0, (*it).find('@'))) != List.end())
{
flag = 1;
cout << " 250" << endl;
}
else
cout << " 550" << endl;
}
if(flag)
{
cout << " DATA" << endl;
cout << " 354" << endl;
cout << text << " ." << endl;
cout << " 250" << endl;
}
cout << " QUIT" << endl;
cout << " 221" << endl;
}
}
return 0;
}
N. Symmetry
題意:
給定平面上n個點,問是否存在一條直線x = k使得這n個點關于x = k對稱。
n <= 1000。
題解:
若存在該直線,則k一定為這n個點橫坐标的平均值,算出來之後檢驗這n個點的對稱點是否存在即可,時間複雜度O(n)。
由于這n個點都是整點,k一定是0.5的倍數,如果想規避浮點數運算的誤差,可以将坐标全部放大兩倍進行整數運算。
代碼:
#include <map>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef pair<int, int> point;
map<point, int> Hash;
int t, n, minx, maxx, xx;
int main()
{
scanf("%d", &t);
while(t--)
{
Hash.clear();
minx = ~0u >> 1, maxx = -minx;
scanf("%d", &n);
for(int i = 0; i < n; ++i)
{
int x, y;
scanf("%d%d", &x, &y);
++Hash[make_pair(x <<= 1, y <<= 1)];
if(x < minx)
minx = x;
if(maxx < x)
maxx = x;
}
xx = minx + maxx;
bool flag = 0;
for(map<point, int>::iterator it = Hash.begin(), jt = Hash.end(); it != jt; ++it)
{
point tmp = it -> first;
tmp.first = xx - tmp.first;
if(Hash.find(tmp) == jt || Hash[tmp] != it -> second)
{
flag = 1;
break;
}
}
puts(flag ? "NO" : "YES");
}
return 0;
}
O. Printer Queue
題意:
給定一個長度為n的操作隊列,對于隊首元素,若優先級為最高,則做該事件,否則将之置于隊尾等待以後操作,現在求第k位的事件會是第幾個被操作的。
題解:
統計每個優先級還剩多少個操作,按照隊列的定義模拟即可,每次找到需要做的操作至多将隊列元素全部周遊一遍,是以時間複雜度O(n^2)。
由于任意時刻隊列的元素個數不超過n,是以可以用循環隊列做到空間複雜度O(n)。
代碼:
#include <cstdio>
const int maxn = 110;
int t, n, pos, que[maxn], l, r, now, cnt[11], ans;
int main()
{
scanf("%d", &t);
while(t--)
{
scanf("%d%d", &n, &pos);
l = 0, r = n, now = 1, ans = 0;
for(int i = 1; i <= 9; ++i)
cnt[i] = 0;
for(int i = 0; i < n; ++i)
{
scanf("%d", que + i);
if(now < que[i])
now = que[i];
++cnt[que[i]];
}
while(l != r)
if(que[l] == now)
{
++ans;
if(l == pos)
break;
--cnt[que[l++]];
if(l >= maxn)
l -= maxn;
while(now && !cnt[now])
--now;
}
else
{
if(l == pos)
pos = r;
que[r++] = que[l++];
if(l >= maxn)
l -= maxn;
if(r >= maxn)
r -= maxn;
}
printf("%d\n", ans);
}
return 0;
}
P. Borrowers
題意:
現在有一個圖書館,藏書按照(作者名, 書名)的形式按字典序排序,現在請你維護三種操作:借書,從藏書中删去某書;還書,将某書放入待整理區;整理,将待整理區的書排序後依次插入藏書,每次輸出插入的位置在哪本書之後,或是插到最前面。
題解:
記錄每本書的作者,待整理區需要整理時排序即可,藏書庫用平衡樹維護,每次查找插入位置即可。
代碼懶得手寫平衡樹,使用了STL的set。設操作數為n,可以做到時間複雜度O(nlogn)。
代碼:
#include <map>
#include <set>
#include <iostream>
#include <algorithm>
using namespace std;
typedef pair<string, string> Book;
map<string, string> Dict;
set<Book> Lib, Rcv;
string tmp1, tmp2;
int main()
{
ios::sync_with_stdio(0);
while(getline(cin, tmp1) && tmp1 != "END")
{
string::size_type pos = tmp1.rfind("\"");
tmp2 = tmp1.substr(pos + 5);
tmp1 = tmp1.substr(1, pos - 1);
Dict[tmp1] = tmp2;
Lib.insert(make_pair(tmp2, tmp1));
}
while(getline(cin, tmp1) && tmp1 != "END")
if(tmp1[0] == 'B')
{
tmp2 = tmp1.substr(8, tmp1.size() - 9);
Lib.erase(make_pair(Dict[tmp2], tmp2));
}
else if(tmp1[0] == 'R')
{
tmp2 = tmp1.substr(8, tmp1.size() - 9);
Rcv.insert(make_pair(Dict[tmp2], tmp2));
}
else
{
for(set<Book>::iterator it = Rcv.begin(), jt = Rcv.end(); it != jt; ++it)
{
set<Book>::iterator pos = Lib.insert(*it).first;
if(pos == Lib.begin())
cout << "Put \"" + it -> second + "\" first" << endl;
else
cout << "Put \"" + it -> second + "\" after \"" + (--pos) -> second + "\"" << endl;
}
cout << "END" << endl;
Rcv.clear();
}
return 0;
}
Q. Bug Hunt
題意:
給定一篇特定的代碼,請你檢查它是否有特定的BUG,若有輸出第一個BUG的行數,若無輸出0。
代碼隻包含一下兩種語句:
<array_name>[<expression>],表示定義一個數組,數組名叫<array_name>,長度為<expression>,下标從0開始。
<array_name>[<expression1>]=<expression2>,表示對數組<array_name>的第<expression1>的位置的元素指派為<expression2>。
其中<array_name>必須是英文字母,<expression>、<expression1>、<expression2>表示表達式,表達式可以是數組元素,也可以是非負整數。
特定的BUG包括下标越界,數組元素未定義,數組未定義三種。
題解:
遞歸求解expression,注意三種BUG的情況即可。
數組可以用map的映射功能代替。
代碼:
#include <map>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
int size[52], now, ans;
map<int, int> array[52];
int trans(char ch)
{
return ch <= 'Z' ? ch - 'A' + 26 : ch - 'a';
}
int GetValue(string a)
{
if(a.find('[') == string::npos)
{
int ret = 0;
for(int i = 0, j = a.size(); i < j; ++i)
ret = (ret << 3) + (ret << 1) + a[i] - '0';
return ret;
}
int name = trans(a[0]), idx = GetValue(a.substr(2, a.size() - 3));
if(idx == -1 || idx >= size[name] || array[name].find(idx) == array[name].end())
return -1;
return array[name][idx];
}
int main()
{
ios::sync_with_stdio(0);
string tmp;
while(cin >> tmp)
if(tmp == ".")
{
if(now)
cout << ans << endl;
ans = now = 0;
for(int i = 0; i < 52; ++i)
if(size[i])
{
array[i].clear();
size[i] = 0;
}
}
else
{
++now;
if(ans)
continue;
string::size_type pos = tmp.find('=');
if(pos == string::npos)
{
int name = trans(tmp[0]), idx = GetValue(tmp.substr(2, tmp.size() - 3));
if(idx == -1)
{
ans = now;
continue;
}
size[name] = idx;
}
else
{
int name = trans(tmp[0]), idx = GetValue(tmp.substr(2, pos - 3)), value = GetValue(tmp.substr(pos + 1));
if(idx == -1 || idx >= size[name] || value == -1)
{
ans = now;
continue;
}
array[name][idx] = value;
}
}
return 0;
}
R. Searching the Web
題意:
給定n篇文章,單詞由英文字母組成,有m個單詞查找操作,操作分為四種:
word,查找帶有word的文章,輸出對應文章内含有term的行。
NOT word,查找不帶有word的文章,輸出整篇文章。
word1 AND word2,查找既帶有word1又帶有word2的文章,輸出對應文章内含有word1或word2的行。
word1 OR word2,查找帶有word1或帶有word2的文章,輸出對應文章内含有word1或word2的行。
查詢結果為空輸出"Sorry, I found nothing.",單次查詢中不同文章之間由一行"----------"分隔,每次查詢末尾帶一行"=========="。
n < 100, m <= 50000, 一行字元數不超過80, 文章行數之和不超過1500。
題解:
對每個單詞記錄每一行是否出現過,按照四種邏輯直接操作即可。
設文章行數之和為k,時間複雜度為O(mk)。
代碼:
#include <map>
#include <bitset>
#include <vector>
#include <string>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxr = 1510, maxc = 88;
bitset<maxr> ZERO(0), ONE(1);
map<string, int> Hash;
int n, r, m, mark[maxr], tot;
vector<bitset<maxr> > mask;
char str[maxr][maxc];
bitset<maxr> flip(bitset<maxr> tmp)
{
return tmp.flip();
}
void Find(string s, bool flag) // ·Ç = 1
{
bitset<maxr> mass(0);
bitset<maxr> &res = Hash.find(s) != Hash.end() ? mask[Hash[s]] : ZERO;
for(int i = 0; i < r; ++i)
mass[mark[i]] = mass[mark[i]] | res[i];
bool flag2 = 1;
for(int i = 0; i < n; ++i)
flag2 &= mass[i];
if(!flag && mass.none() || flag && flag2)
{
puts("Sorry, I found nothing.\n==========");
return;
}
for(int i = 0, last = -1; i < r; ++i)
if(!flag && mass[mark[i]] && res[i] || flag && !mass[mark[i]])
{
if(last != -1 && last != mark[i])
puts("----------");
puts(str[i]);
last = mark[i];
}
puts("==========");
}
void Find(string s, string t, bool flag) // Óë = 0 »ò = 1
{
bitset<maxr> mass1(0), mass2(0), mass(0);
bitset<maxr> &res1 = Hash.find(s) != Hash.end() ? mask[Hash[s]] : ZERO;
bitset<maxr> &res2 = Hash.find(t) != Hash.end() ? mask[Hash[t]] : ZERO;
for(int i = 0; i < r; ++i)
{
mass1[mark[i]] = mass1[mark[i]] | res1[i];
mass2[mark[i]] = mass2[mark[i]] | res2[i];
}
for(int i = 0; i < n; ++i)
mass[i] = flag ? mass1[i] | mass2[i] : mass1[i] & mass2[i];
if(mass.none())
{
puts("Sorry, I found nothing.\n==========");
return;
}
for(int i = 0, last = -1; i < r; ++i)
if(mass[mark[i]] && (res1[i] || res2[i]))
{
if(last != -1 && last != mark[i])
puts("----------");
puts(str[i]);
last = mark[i];
}
puts("==========");
}
int main()
{
char op[5], tmp[maxc << 2], tmp1[maxc], tmp2[maxc];
scanf("%d\n", &n);
for(int t = 0; t < n; ++t)
while(gets(str[r]) != NULL)
{
if(strcmp(str[r], "**********") == 0)
break;
int i, j;
for(i = 0, j = 0; str[r][i]; ++i)
if(str[r][i] >= 'A' && str[r][i] <= 'Z')
tmp[j++] = str[r][i] - 'A' + 'a';
else if(str[r][i] >= 'a' && str[r][i] <= 'z')
tmp[j++] = str[r][i];
else if(j)
{
tmp[j] = '\0';
string temp = tmp;
if(Hash.find(temp) == Hash.end())
{
Hash[temp] = tot++;
mask.push_back(ZERO);
}
mask[Hash[temp]][r] = 1;
j = 0;
}
if(j)
{
tmp[j] = '\0';
string temp = tmp;
if(Hash.find(temp) == Hash.end())
{
Hash[temp] = tot++;
mask.push_back(ZERO);
}
mask[Hash[temp]][r] = 1;
j = 0;
}
mark[r++] = t;
}
scanf("%d\n", &m);
while(m--)
{
gets(tmp);
if(strncmp(tmp, "NOT ", 4) == 0)
{
sscanf(tmp,"%*s%s", tmp1);
Find(tmp1, 1);
}
else if(strchr(tmp, ' ') == NULL)
Find(tmp, 0);
else
{
sscanf(tmp, "%s%s%s", tmp1, op, tmp2);
if(strcmp(op, "AND") == 0)
Find(tmp1, tmp2, 0);
else
Find(tmp1, tmp2, 1);
}
}
return 0;
}
S. Exchange
題意:
有n個操作,操作有三種:
買操作(價格, 數量),添加一個買訂單,并檢查是否有賣訂單比買訂單價格低,按賣訂單價格盡量低、挂訂單時間盡量早的靠前的順序快速買進,輸出交易情況。
賣操作(價格, 數量),添加一個賣訂單,并檢查是否有買訂單比賣訂單價格高,按買訂單價格盡量高、挂訂單時間盡量早的靠前的順序快速賣出,輸出交易情況。
删除操作(标号),删除一個買或賣的訂單,已經交易的部分不做撤銷。
每次操作後輸出目前買訂單最高價以及最高價的産品數量、目前賣訂單最低價以及最低價的産品數量,無訂單時預設買訂單最高價為0,賣訂單最低價為99999。
n <= 10000。
題解:
對于買操作,維護賣訂單以價格排序的小根堆,存儲對于價格的産品數量和按時間戳排序的訂單清單,将買訂單對着賣訂單進行嘗試,嘗試完畢後加入買訂單的堆。
對于賣操作,維護買訂單以價格排序的大根堆,存儲對于價格的産品數量和按時間戳排序的訂單清單,将賣訂單對着買訂單進行嘗試,嘗試完畢後加入賣訂單的堆。
對于删除操作,直接找訂單對應的價格,更新訂單清單和産品數量,訂單清單内的查找可以用二分查找但比較麻煩,可以直接寫一個平衡樹來維護。
時間複雜度O(nlogn),直接用map寫的話常數不是一般的大。
代碼:
#include <map>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 16384;
typedef map<int, int> Order;
typedef pair<int, Order> Orders;
map<int, Orders, greater<int> > Buy;
map<int, Orders, less<int> > Sell;
int n, id, p, q, P[maxn];
template<class A, class B> void Maintain(map<int, Orders, A> &act, map<int, Orders, B> &pass)
{
while(q > 0)
{
if(pass.empty())
break;
map<int, Orders, less<int> >::iterator it = pass.begin();
int pp = it -> first;
B cmp;
if(cmp(p, pp))
break;
Orders &tmp = it -> second;
Order::iterator jt = tmp.second.begin();
int qq = min(q, jt -> second);
printf("TRADE %d %d\n", qq, pp);
q -= qq;
jt -> second -= qq;
tmp.first -= qq;
if(!jt -> second)
tmp.second.erase(jt -> first);
if(!tmp.first)
pass.erase(it -> first);
}
if(q > 0)
if(act.find(p) != act.end())
{
Orders &tmp = act[p];
tmp.first += q;
tmp.second[id] = q;
}
else
{
Order tmp;
tmp.clear();
tmp[id] = q;
act[p] = make_pair(q, tmp);
}
}
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
{
char op[10];
scanf("%s", op);
if(op[0] == 'B' || op[0] == 'S')
{
scanf("%d%d", &q, &p);
P[i] = p;
id = i;
if(op[0] == 'B')
Maintain(Buy, Sell);
else
Maintain(Sell, Buy);
}
else
{
scanf("%d", &id);
if(Buy.find(P[id]) != Buy.end())
{
Orders &tmp = Buy[P[id]];
if(tmp.second.find(id) != tmp.second.end())
{
tmp.first -= tmp.second[id];
tmp.second.erase(id);
}
if(!tmp.first)
Buy.erase(P[id]);
}
if(Sell.find(P[id]) != Sell.end())
{
Orders &tmp = Sell[P[id]];
if(tmp.second.find(id) != tmp.second.end())
{
tmp.first -= tmp.second[id];
tmp.second.erase(id);
}
if(!tmp.first)
Sell.erase(P[id]);
}
}
int bq = 0, bp = 0, sq = 0, sp = 99999;
if(!Buy.empty())
{
map<int, Orders, greater<int> >::iterator it = Buy.begin();
bq = it -> second.first;
bp = it -> first;
}
if(!Sell.empty())
{
map<int, Orders, less<int> >::iterator it = Sell.begin();
sq = it -> second.first;
sp = it -> first;
}
printf("QUOTE %d %d - %d %d\n", bq, bp, sq, sp);
}
return 0;
}
T. Database
題意:
給定n行m列的字元串,每行的字元串之間由','分隔,問是否存在兩行的兩列是一樣的字元串,輸出任意一種可能的情況。
n <= 10000, m <= 10。
題解:
對于每個字元串求出Hash,枚舉答案的兩列,将每一行的兩個字元串Hash值捆綁起來再Hash,看是否存在兩行Hash一樣。
時間複雜度O(nm^2),常數較大,和字元數有關。
代碼:
#include <cstdio>
#include <cstring>
const int maxn = 10010, maxm = 11, maxl = 81, mod1 = 233, mod2 = 23333, mod = 199669;
typedef unsigned long long ULL;
int n, m, tot;
char str[maxl];
ULL Hash1[maxn][maxm];
struct Node
{
int row, nxt;
ULL H1, H2;
} e[maxn];
int Hash[mod];
int main()
{
while(scanf("%d%d\n", &n, &m) == 2)
{
for(int i = 0; i < n; ++i)
{
gets(str);
for(int j = 0, k = 0; j < m && str[k]; ++j)
{
Hash1[i][j] = 0;
for( ; str[k] && str[k] != ','; ++k)
Hash1[i][j] = Hash1[i][j] * mod1 + str[k];
if(str[k] == ',')
++k;
}
}
bool flag = 0;
for(int j = 0; j < m; ++j)
{
for(int k = j + 1; k < m; ++k)
{
tot = 0;
memset(Hash, 0, sizeof Hash);
for(int i = 0; i < n; ++i)
{
int HH = (Hash1[i][j] * mod2 + Hash1[i][k]) % mod, res;
for(int it = Hash[HH]; it; it = e[it].nxt)
if(e[it].H1 == Hash1[i][j] && e[it].H2 == Hash1[i][k])
{
flag = 1;
res = e[it].row;
break;
}
if(flag)
{
puts("NO");
printf("%d %d\n%d %d\n", res + 1, i + 1, j + 1, k + 1);
break;
}
else
{
e[++tot] = (Node){i, Hash[HH], Hash1[i][j], Hash1[i][k]};
Hash[HH] = tot;
}
}
if(flag)
break;
}
if(flag)
break;
}
if(!flag)
puts("YES");
}
return 0;
}
小記
做題順序是GHINDLOKTJBESFPQRAMC,其中FKPRS是FB,沒有按照難度升序來做,看到幾個偏資料結構的題目先做了,模拟題放到了後面慢慢解決。寫代碼還是很慢。