2024.11.27 週三
-
Q1. 1000
給定x,y,設ai=i^x,bi=i^y,問兩個無窮序列a和b的最長公共子序列的長度。 -
Q2. 1400
給定一條鏈,所有點未啟用,在開始點放一棋子並啟用,2人輪流操作:將棋子移動到相鄰的未啟用的點並啟用。不能操作者輸。問均最優策略的贏家。 -
Q3. 1600
給你兩個大小為n×m的矩陣a,b,其中元素的是n×m的排列,你可以任意進行行變換/列變換,問是否透過操作使得矩陣a變成矩陣b。 -
A1. 補:怎麼感覺今天的題1000分的最難 >_<
神秘位運算題 "看到本題的資料範圍,可以猜想這是一道結論題,結合樣例就出了。"
[l,r]⊕x=[l′,r′]⊕y => [l,r]=[l′,r′]⊕(x⊕y)。令v=(x⊕y),即求最長的 [l,r]使得異或上v後依然連續。
如果 v=abc100000,任意 l=cde100000,r=cde111111一定是最長的,答案為lowbit(v)。 -
A2. 補:我就說對不上樣例得"仔細"重讀題吧,讀漏了。
顯然只有第一步操作有2種選擇,其餘操作沒有選擇,且奇數為必勝態。直接搜尋兩側鏈的點數,若有奇數便可勝。 -
A3. 13mins-33mins 假思路:最初的想法是判斷每一行的和和每一列的和,但是不嚴謹。行和只是必要條件,非充分。後又想到用行首元素vector存其餘元素,然後發現判斷困難。
發現無論怎麼交換同一行和同一列中的元素種類是不會改變的,只會改變相對位置。 因此答案就是判斷a中每一行和每一列在b中是否有無序版。
判斷方式多樣如雜湊,我這裡直接使用並查集把a每一行看成一個集合,在b中判斷是否衝突,列同理。
A1.
#include <bits/stdc++.h>
#define int long long //
#define endl '\n' //
using namespace std;
#define bug(BUG) cout << "bug:# " << (BUG) << endl
#define bug2(BUG1, BUG2) cout << "bug:# " << (BUG1) << " " << (BUG2) << endl
#define bug3(BUG1, BUG2, BUG3) cout << "bug:# " << (BUG1) << ' ' << (BUG2) << ' ' << (BUG3) << endl
const int mod = 998244353;
const int N = 10 + 5e5;
void _();
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
_();
return 0;
}
// 給定x,y,設ai=i^x,bi=i^y,問兩個無窮序列a和b的最長公共子序列的長度。
// 神秘位運算題 "看到本題的資料範圍,可以猜想這是一道結論題,結合樣例就出了。"
// [l,r]⊕x=[l′,r′]⊕y => [l,r]=[l′,r′]⊕(x⊕y)。令v=(x⊕y),即求最長的 [l,r]使得異或上v後依然連續。
// 如果 v=abc100000,任意 l=cde100000,r=cde111111一定是最長的,答案為lowbit(v)。
void _()
{
int x, y;
cin >> x >> y;
auto lowbit = [](int x)
{
return x & -x;
};
cout << lowbit(x ^ y) << endl;
}
A2.
#include <bits/stdc++.h>
// #define int long long //
#define endl '\n' // 互動/除錯 關
using namespace std;
#define bug(BUG) cout << "bug:# " << (BUG) << endl
#define bug2(BUG1, BUG2) cout << "bug:# " << (BUG1) << " " << (BUG2) << endl
#define bug3(BUG1, BUG2, BUG3) cout << "bug:# " << (BUG1) << ' ' << (BUG2) << ' ' << (BUG3) << endl
void _();
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T = 1;
// cin >> T;
while (T--)
_();
return 0;
}
// 給定一條鏈,所有點未啟用,在開始點放一棋子並啟用,2人輪流操作:將棋子移動到相鄰的未啟用的點並啟用。不能操作者輸。問均最優策略的贏家。
// 我就說對不上樣例得"仔細"重讀題吧,讀漏了。
// 顯然只有第一步操作有2種選擇,其餘操作沒有選擇,且奇數為必勝態。直接搜尋兩側鏈的點數,若有奇數便可勝。
void _()
{
int n, t;
cin >> n >> t;
vector<vector<int>> e(n + 1);
for (int i = 1; i < n; i++)
{
int u, v;
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
int st = 0;
cin >> st;
vector<int> vis(n + 1);
function<int(int)> dfs = [&](int u)
{
if (vis[u])
return 0;
vis[u] = 1;
int cnt = 1;
for (auto v : e[u])
cnt += dfs(v);
return cnt;
};
vis[st] = 1;
bool f = 0;
for (auto u : e[st])
if (dfs(u) & 1)
f = 1;
cout << (f ? "Ron" : "Hermione") << endl;
}
A3.
#include <bits/stdc++.h>
#define int long long //
#define endl '\n' // 互動/除錯 關
using namespace std;
#define bug(BUG) cout << "bug:# " << (BUG) << endl
#define bug2(BUG1, BUG2) cout << "bug:# " << (BUG1) << " " << (BUG2) << endl
#define bug3(BUG1, BUG2, BUG3) cout << "bug:# " << (BUG1) << ' ' << (BUG2) << ' ' << (BUG3) << endl
void _();
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
while (T--)
_();
return 0;
}
// 給你兩個大小為n×m的矩陣a,b,其中元素的是n×m的排列,你可以任意進行行變換/列變換,問是否透過操作使得矩陣a變成矩陣b。
// 假思路:最初的想法是判斷每一行的和和每一列的和,但是不嚴謹。行和只是必要條件,非充分。後又想到用行首元素vector存其餘元素,然後發現判斷困難。
// 發現無論怎麼交換同一行和同一列中的元素種類是不會改變的,只會改變相對位置。 因此答案就是判斷a中每一行和每一列在b中是否有無序版。
// 判斷方式多樣如雜湊,我這裡直接使用並查集把a每一行看成一個集合,在b中判斷是否衝突,列同理。
// 13mins-33mins
// 帶權並查集
vector<int> p, vs, es; // 集合數 點數 邊數 (對一個連通塊而言)
void init(int n1) // p[x]不一定為根節點 find(x)一定是根節點
{
int n = n1 + 2;
p.assign(n, 0);
vs.assign(n, 0);
es.assign(n, 0);
for (int i = 1; i <= n1; i++)
p[i] = i, vs[i] = 1, es[i] = 0;
}
int find(int x) // 找到根節點
{
if (p[x] == x)
return x;
int px = find(p[x]);
return p[x] = px;
}
bool same(int a, int b)
{
return find(a) == find(b);
}
void merge(int a, int b) // 合併集合
{
int pa = find(a);
int pb = find(b);
if (pa == pb) // pa pb 均為根節點 p[pa]==pa
{
es[pa]++; // 1個集合 邊+1
return;
}
p[pb] = p[pa]; // 改變b的根節點
vs[pa] += vs[pb]; // 將b合併進a
es[pa] += es[pb] + 1; // 2個集合
}
int size(int a) // 集合內的元素的個數
{
return vs[find(a)];
}
// init(n);
void _()
{
int n, m;
cin >> n >> m;
init(n * m);
vector<vector<int>> a(n + 1, vector<int>(m + 1)), b(n + 1, vector<int>(m + 1));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
cin >> a[i][j];
if (j - 1)
merge(a[i][j], a[i][1]);
}
bool f = 1;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
cin >> b[i][j];
if (j - 1 && !same(b[i][j], b[i][1]))
f = 0;
}
}
init(n * m);
for (int j = 1; j <= m; j++)
for (int i = 1; i <= n; i++)
if (i - 1)
merge(a[i][j], a[1][j]);
for (int j = 1; j <= m; j++)
for (int i = 1; i <= n; i++)
if (i - 1 && !same(b[i][j], b[1][j]))
f = 0;
cout << (f ? "YES" : "NO") << endl;
}
// void _()
// {
// int n, m;
// cin >> n >> m;
// vector<vector<int>> a(n + 1, vector<int>(m + 1)), b(n + 1, vector<int>(m + 1));
// map<int, vector<int>> a_row, b_row;
// for (int i = 1; i <= n; i++)
// {
// int x;
// for (int j = 1; j <= m; j++)
// {
// cin >> a[i][j];
// if (j == 1)
// x = a[i][j];
// a_row[x].push_back(a[i][j]);
// }
// }
// for (int i = 1; i <= n; i++)
// {
// int x;
// for (int j = 1; j <= m; j++)
// {
// cin >> b[i][j];
// if (j == 1)
// x = b[i][j];
// b_row[x].push_back(b[i][j]);
// }
// }
// bool f = 1;
// for (auto &[x, a] : a_row)
// {
// auto &b = b_row[x];
// sort(a.begin(), a.end());
// sort(b.begin(), b.end());
// if (a != b)
// f = 0;
// }
// cout << (f ? "YES" : "NO") << endl;
// }
// void _()
// {
// int n, m;
// cin >> n >> m;
// vector<vector<int>> a(n + 1, vector<int>(m + 1)), b(n + 1, vector<int>(m + 1));
// map<int, int> a_row, b_row, a_col, b_col;
// for (int i = 1; i <= n; i++)
// {
// int s = 0;
// for (int j = 1; j <= m; j++)
// {
// cin >> a[i][j];
// s += a[i][j];
// }
// a_row[s]++;
// }
// for (int i = 1; i <= n; i++)
// {
// int s = 0;
// for (int j = 1; j <= m; j++)
// {
// cin >> b[i][j];
// s += b[i][j];
// }
// b_row[s]++;
// }
// for (int j = 1; j <= m; j++)
// {
// int s = 0;
// for (int i = 1; i <= n; i++)
// s += a[i][j];
// a_col[s]++;
// }
// for (int j = 1; j <= m; j++)
// {
// int s = 0;
// for (int i = 1; i <= n; i++)
// s += b[i][j];
// b_col[s]++;
// }
// int f = 1;
// for (auto [s, cnt] : a_row)
// if (cnt - b_row[s])
// f = 0;
// for (auto [s, cnt] : a_col)
// if (cnt - b_col[s])
// f = 0;
// cout << (f ? "YES" : "NO") << endl;
// }