Codeforces Round 934 (Div. 2)

value0發表於2024-03-17

Codeforces Round 934 (Div. 2)

A - Destroying Bridges

解題思路:

完全圖每個點的連邊數為\(n - 1\)

  • \(k < n - 1\):都可到達。
  • \(k \geq n - 1\):將點\(1\)的邊刪完,只能呆在點\(1\)

程式碼:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using piii = pair<ll, pair<ll, ll>>;
const ll inf = 1ll << 60;
using ull = unsigned long long;
const int mod = 998244353;

void solve()
{
    int n, k;
    cin >> n >> k;
    if (k >= n - 1)
    {
        cout << 1 << endl;
    }
    else
    {
        cout << n << endl;
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

B - Equal XOR

解題思路:

對於每個數字只有三種情況:

  • 只出現在\((1, n)\)
  • 只出現在\((n + 1, 2 n)\)
  • 一個出現在\((1, n)\),另一個出現在\(n + 1, 2n\)

前兩種情況數目肯定是相同的。

我們先用前兩種成對分別填入\(l,r\)中,不夠的再用第三種補,整個過程都是同步的。

程式碼:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using piii = pair<ll, pair<ll, ll>>;
const ll inf = 1ll << 60;
using ull = unsigned long long;
const int mod = 998244353;

void solve()
{
    int n, k;
    cin >> n >> k;
    vector<int> a(2 * n + 2);
    for (int i = 1; i <= 2 * n; i++)
    {
        cin >> a[i];
    }
    vector<int> l, r;
    vector<int> vis(2 * n + 10);
    // 2, 3, 4
    for (int i = 1; i <= n; i++)
    {
        vis[a[i]] += 1;
    }
    for (int i = n + 1; i <= 2 * n; i++)
    {
        vis[a[i]] += 2;
    }
    vector<int> ls, rs, t;
    for (int i = 1; i <= n; i++)
    {
        if (vis[a[i]] == 3)
        {
            t.push_back(a[i]);
        }
        else if (vis[a[i]] == 2)
        {
            ls.push_back(a[i]);
        }
    }
    for (int i = n + 1; i <= 2 * n; i++)
    {
        if (vis[a[i]] == 4)
        {
            rs.push_back(a[i]);
        }
    }
    sort(ls.begin(), ls.end());
    ls.erase(unique(ls.begin(), ls.end()), ls.end());
    sort(rs.begin(), rs.end());
    rs.erase(unique(rs.begin(), rs.end()), rs.end());
    for (int i = 0; i < min(ls.size(), rs.size()) && l.size() < 2 * k; i++)
    {
        l.push_back(ls[i]);
        l.push_back(ls[i]);
        r.push_back(rs[i]);
        r.push_back(rs[i]);
    }
    for (int i = 0; i < t.size() && l.size() < 2 * k; i++)
    {
        l.push_back(t[i]);
        r.push_back(t[i]);
    }
    // int t1 = 0;
    // int t2 = 0;
    for (auto x : l)
    {
        cout << x << ' ';
        // t1 ^= x;
    }
    cout << "\n";
    for (auto x : r)
    {
        cout << x << ' ';
        // t2 ^= x;
    }
    cout << "\n";
    // if (t1 == t2)
    // {
    //     puts("YES");
    // }
    // // for (int i = 1; i <= n; i++)
    // // {
    // //     t1 ^= a[i];
    // // }
    // for (int i = n + 1; i <= 2 * n; i++)
    // {
    //     t2 ^= a[i];
    // }
    // cout << t1 << ' ' << t2 << endl;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

C - MEX Game 1

解題思路:

出現次數大於\(1\)次的,無論先後手肯定都能搶到。

所以我們按照\(mex\),從小到大優先拿出現次數為\(1\)的。

程式碼:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using piii = pair<ll, pair<ll, ll>>;
const ll inf = 1ll << 60;
using ull = unsigned long long;
const int mod = 998244353;

void solve()
{
    int n;
    cin >> n;
    vector<int> a(n + 1);
    map<int, int> cnt;
    vector<bool> vis(n + 1);
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        cnt[a[i]]++;
    }
    for (auto t : cnt)
    {
        if (t.se >= 2)
        {
            vis[t.fi] = true;
        }
    }
    int cur = 0;
    while (vis[cur])
    {
        cur++;
    }
    for (int i = 1; i <= n; i++)
    {
        while (vis[cur])
        {
            cur++;
        }
        if (cnt[cur] == 1)
        {
            cnt[cur]--;
            vis[cur] = true;
        }
        else
        {
            break;
        }
        while (vis[cur])
        {
            cur++;
        }
        if (cnt[cur] == 1)
        {
            cnt[cur]--;
        }
    }
    int ans = 0;
    while (vis[ans])
    {
        ans++;
    }
    cout << ans << endl;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

D - Non-Palindromic Substring

解題思路:

\(len = r - l + 1\)

  • \(k = 1\):肯定迴文。
  • \(k = len\):單獨判斷
  • \(2 \leq k \leq len - 1\)
    • \(k\)為奇數:只要整個區間不是\(aba...aba\)這種交叉形式,奇數子串一定都存在。如果\(k = 3\)不存在,意味著整個區間都是\(aba...aba\)這種交叉形式。
    • \(k\)為偶數:只要整個區間字元不是都一樣,偶數子串一定都存在。如果\(k = 2\)不存在,意味著整個區間都是一樣的。

注意:本題疑似卡了單雜湊,如果要用雜湊判斷整體是否迴文,建議使用雙雜湊對映。

判斷整體迴文:\(manacher\);雙雜湊

判斷奇數是否存在:

  • 思路一:\(f[i]:記錄右側奇偶性相同的下標中,第一個不同的字元的位置\)\((f[l] \leq r || f[l + 1]\leq r)\)
  • 思路二:雜湊判斷\((l, r - 2)和(l + 2, r)\)是否完全相同。

判斷偶數是否存在:

  • 思路一:\(f[i]:記錄右側第一個不同的字元的位置\)\((f[l] \leq r)\)
  • 思路二:區間最大最小值相同。

程式碼:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using piii = pair<ll, pair<ll, ll>>;
const ll inf = 1ll << 60;
using ull = unsigned long long;
const int P = 13331;
std::vector<int> manacher(std::string s)
{
    std::string t = "#";
    for (auto c : s)
    {
        t += c;
        t += '#';
    }
    int n = t.size();
    std::vector<int> r(n);
    for (int i = 0, j = 0; i < n; i++)
    {
        if (2 * j - i >= 0 && j + r[j] > i)
        {
            r[i] = std::min(r[2 * j - i], j + r[j] - i);
        }
        while (i - r[i] >= 0 && i + r[i] < n && t[i - r[i]] == t[i + r[i]])
        {
            r[i] += 1;
        }
        if (i + r[i] > j + r[j])
        {
            j = i;
        }
    }
    return r;
}

void solve()
{
    int n, q;
    cin >> n >> q;
    string s;
    cin >> s;
    auto rad = manacher(s);
    string str = s;
    s = ' ' + s;
    vector<ull> h(n + 1), p(n + 1), h1(n + 10);
    p[0] = 1;
    for (int i = 1; i <= n; i++)
    {
        p[i] = p[i - 1] * P;
        h[i] = h[i - 1] * P + s[i];
    }
    reverse(str.begin(), str.end());
    str = ' ' + str;
    for (int i = 1; i <= n; i++)
    {
        h1[i] = h1[i - 1] * P + str[i];
    }
    auto get1 = [&](int l, int r) -> ull
    {
        return h[r] - h[l - 1] * p[r - l + 1];
    };
    auto get2 = [&](int l, int r) -> ull
    {
        return h1[r] - h1[l - 1] * p[r - l + 1];
    };
    vector<vector<int>> f(n + 1, vector<int>(22)), g(n + 1, vector<int>(22, 1e9));
    for (int j = 0; (1 << j) <= n; j++)
    {
        for (int i = 1; i + (1 << j) - 1 <= n; i++)
        {
            if (j == 0)
            {
                f[i][j] = s[i];
            }
            else
            {
                f[i][j] = max(f[i][j - 1], f[i + (1 << j - 1)][j - 1]);
            }
        }
    }
    auto q1 = [&](int l, int r)
    {
        int len = (r - l + 1);
        int k = log(len) / log(2);
        return max(f[l][k], f[r - (1 << k) + 1][k]);
    };
    for (int j = 0; (1 << j) <= n; j++)
    {
        for (int i = 1; i + (1 << j) - 1 <= n; i++)
        {
            if (j == 0)
            {
                g[i][j] = s[i];
            }
            else
            {
                g[i][j] = min(g[i][j - 1], g[i + (1 << j - 1)][j - 1]);
            }
        }
    }
    auto q2 = [&](int l, int r)
    {
        int len = (r - l + 1);
        int k = log(len) / log(2);
        return min(g[l][k], g[r - (1 << k) + 1][k]);
    };

    while (q--)
    {
        int l, r;
        cin >> l >> r;
        ll len = r - l + 1;
        ll ans = 0;
        // if (len & 1)
        // {
        //     ll t = len / 2;
        //     if (get1(l, l + t - 1) != get2(n - r + 1, n - (l + t + 1) + 1))
        //     {
        //         ans += len;
        //     }
        // }
        // else
        // {
        //     ll t = len / 2;
        //     if (get1(l, l + t - 1) != get2(n - r + 1, n - (l + t) + 1))
        //     {
        //         ans += len;
        //     }
        // }
        // cout << ans << endl;
        if (rad[l + r - 1] <= len)
        {
            ans += len;
        }
        if (q1(l, r) != q2(l, r))
        {
            ll up = len;
            if (len & 1)
            {
                up--;
            }
            else
            {
                up -= 2;
            }
            ll k = up / 2;
            ans += (2 + up) * k / 2;
        }
        if (len > 3 && get1(l, r - 2) != get1(l + 2, r))
        {
            ll up = len;
            if (len & 1)
            {
                up -= 2;
            }
            else
            {
                up--;
            }
            ll k = up / 2;
            ans += (3 + up) * k / 2;
        }
        cout << ans << "\n";
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

相關文章