2024.11.27 周三

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;
// }
posted @ 2024-11-27 19:02  move_quiet  阅读(4)  评论(0编辑  收藏  举报