Loading

解题报告 ABC398

省流:1575pts,rk2219。

A.

显然直接把 = 构造到中间,\(n\) 是奇数时放一个 =,否则放两个 =

#include <bits/stdc++.h>
using namespace std;

#define endl '\n'
#define int long long

const int maxn = 100 + 10;

int n;

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    cin >> n;
    int x = n / 2;
    if (n % 2)
    {
        for (int i = 1; i <= x; i++)
            cout << '-';
        cout << '=';
        for (int i = 1; i <= x; i++)
            cout << '-';
    }
    else
    {
        for (int i = 1; i <= x - 1; i++)
            cout << '-';
        cout << "==";
        for (int i = 1; i <= x - 1; i++)
            cout << '-';
    }
    return 0;
}

B.

只要统计是否存在两种牌 \(i,j\) 满足出现次数 \(cnt_i\ge 3,cnt_j\ge 2\) 就行。

实现上五花八门。这里选择开桶读入后进行排序。

#include <bits/stdc++.h>
using namespace std;

#define endl '\n'
#define int long long

const int maxn = 13 + 10;

int cnt[maxn];

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    for (int i = 1; i <= 7; i++)
    {
        int x;
        cin >> x;
        cnt[x]++;
    }
    sort(cnt + 1, cnt + 13 + 1, [](int a, int b)
         { return a > b; });
    if (cnt[1] >= 3 && cnt[2] >= 2)
        cout << "Yes" << endl;
    else
        cout << "No" << endl;
    return 0;
}

C.

读入时开桶标记 \(a_i\) 有重复的,然后直接扫一遍。

#include <bits/stdc++.h>
using namespace std;

#define endl '\n'
#define int long long

const int maxn = 300'000 + 10;

int n;
int a[maxn];
unordered_map<int, int> cnt;

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        cnt[a[i]]++;
    }
    int maxa = -1, maxi = -1;
    for (int i = 1; i <= n; i++)
    {
        if (cnt[a[i]] != 1)
            continue;
        if (a[i] > maxa)
        {
            maxa = a[i];
            maxi = i;
        }
    }
    cout << maxi << endl;
    return 0;
}

D.

注意到让烟动的复杂度是不可承受的,所以我们反过来让人动,并记录到原点的偏移量来维护原点。

实现上可以使用 map<pair<int, int>, bool> 存储每一个位置是否有烟。这里不知道为什么用 unordered_map CE了。

但是怎么还有那么多人想不到这个存图方式。

E.

注意到一个没有奇环的图是二分图。

对图进行染色分为两个集合 \(A,B\),易知游戏结束时图中共有 \(|A|\times |B|\) 条边。由于原有 \(n-1\) 条边,总的操作次数 \(cnt=|A|\times|B|-n+1\)

显然 \(cnt\) 为奇数时先手必胜,否则后手必胜。

对于加边操作,我们使用 set 存储所有可加的边,每次随机取出一条即可。这里取的是第一条。

#include <bits/stdc++.h>
using namespace std;

#define int long long

const int maxn = 100 + 10;

int n;
vector<int> e[maxn];
bool g[maxn][maxn];

int col[maxn];
vector<int> a, b;

set<pair<int, int>> s;

void BFS(int u)
{
    queue<int> Q;
    col[u] = 0;
    Q.push(u);
    while (!Q.empty())
    {
        int u = Q.front();
        Q.pop();
        for (auto v : e[u])
            if (col[v] == -1)
            {
                col[v] = col[u] ^ 1;
                Q.push(v);
            }
    }
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    cin >> n;
    for (int i = 1; i <= n - 1; i++)
    {
        int u, v;
        cin >> u >> v;
        e[u].push_back(v);
        e[v].push_back(u);
        g[u][v] = g[v][u] = true;
    }
    memset(col, -1, sizeof col);
    BFS(1);
    for (int i = 1; i <= n; i++)
        if (!col[i])
            a.push_back(i);
        else
            b.push_back(i);
    for (int i = 1; i < n; i++)
        for (int j = i + 1; j <= n; j++)
        {
            if (col[i] != col[j] && g[i][j] == 0)
            {
                s.insert(make_pair(i, j));
                s.insert(make_pair(j, i));
            }
        }
    int cnt = a.size() * b.size() - n + 1;
    if (cnt % 2)
    {
        cout << "First" << endl;
        int u = (*s.begin()).first, v = (*s.begin()).second;
        cout << u << " " << v << endl;
        s.erase(make_pair(u, v));
        s.erase(make_pair(v, u));
    }
    else
        cout << "Second" << endl;
    while (true)
    {
        int u, v;
        cin >> u >> v;
        if (u == -1 && v == -1)
            break;
        s.erase(make_pair(u, v));
        s.erase(make_pair(v, u));
        u = (*s.begin()).first, v = (*s.begin()).second;
        cout << u << " " << v << endl;
        s.erase(make_pair(u, v));
        s.erase(make_pair(v, u));
    }
    return 0;
}

F.

注意到本质上是求一个最长后缀回文子串。

可以正逆序各求一遍哈希,然后暴力枚举这个子串的长度进行处理。

KMP 和马拉车好像也可做。反正随便乱搞一下就过掉了。

#include <bits/stdc++.h>
using namespace std;

#define endl '\n'
#define int unsigned long long

const int maxn = 500000 + 10;
const int base = 13331;

string s, r;
int n;

int h1[maxn], h2[maxn];

int qpow(int a, int b)
{
    int res = 1;
    while (b > 0)
    {
        if (b & 1)
            res = res * a;
        a = a * a;
        b >>= 1;
    }
    return res;
}

int get_hash1(int l, int r) { return h1[r] - h1[l - 1] * qpow(base, r - l + 1); }
int get_hash2(int l, int r) { return h2[l] - h2[r + 1] * qpow(base, r - l + 1); }

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    cin >> s;
    n = s.size();
    s = " " + s;
    for (int i = 1; i <= n; i++)
        r += s[i];
    r = " " + r + " ";
    for (int i = 1; i <= n; i++)
        h1[i] = h1[i - 1] * base + s[i];
    for (int i = n; i >= 1; i--)
        h2[i] = h2[i + 1] * base + r[i];
    int maxl = 1;
    for (int len = 2; len <= n; len++)
    {
        if (len % 2)
        {
            int l = len / 2;
            if (get_hash1(n - l + 1, n) == get_hash2(n - 2 * l, n - l - 1))
                maxl = len;
        }
        else
        {
            int l = len / 2;
            if (get_hash1(n - l + 1, n) == get_hash2(n - 2 * l + 1, n - l))
                maxl = len;
        }
    }
    for (int i = 1; i <= n; i++)
        cout << s[i];
    for (int i = n - maxl; i >= 1; i--)
        cout << s[i];
    return 0;
}

G.

连通块间处理不会。弃了。

posted @ 2025-03-22 22:05  Merlin_Meow  阅读(17)  评论(0)    收藏  举报
Sakana Widget 自定义角色自适应示例