2024牛客寒假算法基础集训营3

A-智乃与瞩目狸猫、幸运水母、月宫龙虾

#include<bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;
using i128 = __int128;
using ldb = long double;

#define int i64

using vi = vector<int>;

using pii = pair<int, int>;
using vii = vector<pii>;

const int inf = INT_MAX, INF = 1e18;
const int mod = 998244353;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
using edge = array<int, 3>;

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n;
    cin >> n;
    string a , b;
    for( int x , y ; n ; n -- ){
        cin >> a >> b;
        x = a[0] , y = b[0];
        if( x >= 'A' and x <= 'Z' ) x = x + 'a' - 'A';
        if( y >= 'A' and y <= 'Z' ) y = y + 'a' - 'A';
        if( x == y ) cout << "Yes\n";
        else cout << "No\n";
    }

}

B-智乃的数字手串

模二后,把序列按照连续相同进行分段,并且如果第一段和最后一段相同则要合并成一段,如果一共分成了cnt段,则整体可进行的操作次数就是n-cnt。但是要注意如果只有一段则可以进行n次操作。

#include<bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;
using i128 = __int128;
using ldb = long double;

#define int i64

using vi = vector<int>;

using pii = pair<int, int>;
using vii = vector<pii>;

const int inf = INT_MAX, INF = 1e18;
const int mod = 998244353;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
using edge = array<int, 3>;

void solve() {
    int n;
    cin >> n;
    vi a(n);
    for (auto &i: a) cin >> i, i %= 2;
    int cnt = 1 , res ;
    for (int i = 1; i < n; i++)
        if (a[i] != a[i - 1]) cnt++;
    if (cnt > 2 and a.front() == a.back()) cnt--;
    if( cnt == 1 ) res = n;
    else res = n - cnt;
    if( res % 2 ) cout << "qcjj\n";
    else cout << "zn\n";
    return;
}

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int TC;
    for (cin >> TC; TC; TC--)
        solve();
}

C-智乃的前缀、后缀、回文

其实是是一个字符串模板题了算是,所以我用了两个字符串算法来求解。

首先用 Manacher 求出\(S\)串所有的前缀回文串和后缀回文串,然后用字符串哈希判断每一个\(S\)的前缀前缀是否与\(T\)的后缀相同,每一个\(S\)的后缀是否与\(T\)的前缀相同。

处理选择我先处理出后缀最大值,然后计算前缀的时候直接与后缀最大值一起更新答案即可。

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;
using vi = vector<i64>;


namespace Hash {
    // 下标从 1 开始
    using Val = pair<i64, i64>;
    const Val Mod(1e9 + 7, 1e9 + 9);
    const Val base(13331, 23333);
    vector<Val> p;

    Val operator+(Val a, Val b) {
        i64 c1 = a.first + b.first, c2 = a.second + b.second;
        if (c1 >= Mod.first) c1 -= Mod.first;
        if (c2 >= Mod.second) c2 -= Mod.second;
        return pair(c1, c2);
    }

    Val operator-(Val a, Val b) {
        i64 c1 = a.first - b.first, c2 = a.second - b.second;
        if (c1 < 0) c1 += Mod.first;
        if (c2 < 0) c2 += Mod.second;
        return pair(c1, c2);
    }

    Val operator*(Val a, Val b) {
        return pair(a.first * b.first % Mod.first, a.second * b.second % Mod.second);
    }

    void init(int n) {
        p.resize(n + 1), p[0] = pair(1, 1);
        for (int i = 1; i <= n; i++) p[i] = p[i - 1] * base;
        return;
    }

    struct Hash {
        vector<Val> h;

        Hash(const string &s) {
            h.resize(s.size() + 1);
            for (int i = 1; i <= s.size(); i++)
                h[i] = h[i - 1] * base + pair(s[i - 1], s[i - 1]);
            return;
        }

        Val getHash(int l, int r) {
            if (l > r) return pair(0, 0);
            return h[r] - h[l - 1] * p[r - l + 1];
        }

        Val val() {
            return h.back();
        }
    };

}


const int N = 1e5;


string manacherInit(const string &s) {
    string t = "#";
    for (const char &c: s)
        t += c, t += '#';
    return t;
}

vector<int> manacher(const string &s) {
    int n = s.size();
    vector<int> p(n);
    for (int i = 0, j = 0; i < n; i++) {
        if (j + p[j] > i) p[i] = min(p[j * 2 - i], j + p[j] - i);
        while (i >= p[i] and i + p[i] < n and s[i - p[i]] == s[i + p[i]]) p[i]++;
        if (i + p[i] > j + p[j]) j = i;
    }
    return p;
}


int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    Hash::init(N);
    int n, m;
    cin >> n >> m;
    string s, t;
    cin >> s >> t;
    if (n > m) swap(n, m), swap(s, t);
    auto p = manacher(manacherInit(s));

    vi pm, sm;
    for (int i = 1; i < n; i++) {
        if (p[i] > i) pm.push_back(i);
        if (p[n * 2 - i] > i) sm.push_back(i);
    }

    Hash::Hash hs(s), ht(t);

    vi sufVal(n + 1, -1);
    for (auto len: sm) {
        if (ht.getHash(1, len) == hs.getHash(n - len + 1, n))
            sufVal[n - len + 1] = len;
    }
    for (int i = n - 1; i >= 1; i--) sufVal[i] = max(sufVal[i], sufVal[i + 1]);

    i64 res = -1;
    for (auto len: pm) {
        if (sufVal[len + 1] == -1) break;

        if (hs.getHash(1, len) == ht.getHash(m - len + 1, m))
            res = max(res, len + sufVal[len + 1]);
    }
    if (res > 0) cout << res * 2 << "\n";
    else cout << "-1\n";
    return 0;
}

当然了,判断回文串也可以逆序哈希求解。

D-chino's bubble sort and maximum subarray sum(easy version)

直接枚举交换的位置即可。

#include<bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;
using i128 = __int128;
using ldb = long double;

#define int i64

using vi = vector<int>;

using pii = pair<int, int>;
using vii = vector<pii>;

const int inf = INT_MAX, INF = 1e18;
const int mod = 998244353;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
using edge = array<int, 3>;

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n, k;
    cin >> n >> k;
    vi a(n);
    for (auto &i: a) cin >> i;

    auto calc = [&a]() {
        int ans = -inf;
        for (int i = 0, cnt = 0; i < a.size(); i++) {
            cnt += a[i];
            ans = max(ans, cnt);
            if (cnt < 0) cnt = 0;
        }
        return ans;
    };
    if (k == 0)
        cout << calc() << "\n";
    else {
        int res = -inf;
        for (int i = 1; i < n; i++) {
            swap(a[i - 1], a[i]);
            res = max(res, calc());
            swap(a[i - 1], a[i]);
        }
        cout << res << "\n";
    }
}

G-智乃的比较函数(easy version)

可以直接枚举三个数赋值

#include<bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;
using i128 = __int128;
using ldb = long double;

#define int i64

using vi = vector<int>;

using pii = pair<int, int>;
using vii = vector<pii>;

const int inf = INT_MAX, INF = 1e18;
const int mod = 998244353;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
using edge = array<int, 3>;

void solve() {
    int n;
    cin >> n;
    vector<array<i32, 3>> b(n);
    for (auto &it: b)
        for (auto &i: it) cin >> i;
    vector<int> a(4);
    auto check = [&a, &b]() {
        for (const auto &[x, y, z]: b)
            if ((a[x] < a[y]) != z) return false;
        return true;
    };
    for (a[1] = 0; a[1] <= 2; a[1]++)
        for (a[2] = 0; a[2] <= 2; a[2]++)
            for (a[3] = 0; a[3] <= 2; a[3]++)
                if (check()) {
                    cout << "Yes\n";
                    return;
                }

    cout << "No\n";
}

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int TC;
    for (cin >> TC; TC; TC--)
        solve();
    return 0;
}

H-智乃的比较函数(normal version)

同 G

J-智乃的相亲活动

其实可以分开算每个女生不选某个男生的概率,分别累乘就可以计算出一个男生不被所有女生选中期望,然后就可以算出被选男生的数量的期望。女生同理。

#include<bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;
using i128 = __int128;
using ldb = long double;

#define int i64

using vi = vector<int>;

using pii = pair<int, int>;
using vii = vector<pii>;

const int inf = INT_MAX, INF = 1e18;
const int mod = 998244353;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
using edge = array<int, 3>;

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n, m, k;
    cin >> n >> m >> k;
    vector<vi> manToFemale(n), femaleToMan(m);
    for (int x, y; k; k--) {
        cin >> x >> y, --x, --y;
        manToFemale[x].push_back(y);
        femaleToMan[y].push_back(x);
    }
    vector<ldb> notMan(n, 1.0), notFemale(m, 1.0);
    for (const auto &it: manToFemale)
        for (const auto &i: it)
            notFemale[i] *= (ldb) (it.size() - 1) / (it.size());
    for (const auto &it: femaleToMan)
        for (const auto i: it)
            notMan[i] *= (ldb) (it.size() - 1) / (it.size());
    ldb eMan = 0, eFemale = 0;
    for (const auto &i: notMan)
        eMan += 1.0 - i;
    for (const auto &i: notFemale)
        eFemale += 1.0 - i;
    cout << "float\n" << fixed << setprecision(10) << eMan << " " << eFemale << "\n";
    return 0;
}

k-智乃的“黑红树”

构造起来还算简单,简单思路就是用两个队列分别进行 bfs。如果最后点凑不够就是无解。

#include<bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;
using i128 = __int128;
using ldb = long double;

#define int i64

using vi = vector<int>;

using pii = pair<int, int>;
using vii = vector<pii>;

const int inf = INT_MAX, INF = 1e18;
const int mod = 998244353;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
using edge = array<int, 3>;

void solve() {
    int a, b, n;// black red
    cin >> a >> b, n = a + b;
    if( a == 0 ) {
        cout << "No\n";
        return;
    }
    vector<vi> tree(n + 1, vi(2, -1));
    queue<int> redLeaf, blackLeaf;
    blackLeaf.push(1), a--;
    for (int f = 0, t = 1, x; a + b > 0; f = 0) {
        while (not blackLeaf.empty() and b >= 2 and t + 2 <= n) {
            f |= 1, x = blackLeaf.front(), b -= 2, blackLeaf.pop();
            tree[x][0] = ++t, redLeaf.push(t);
            tree[x][1] = ++t, redLeaf.push(t);
        }
        while (not redLeaf.empty() and a >= 2 and t + 2 <= n) {
            f |= 1, x = redLeaf.front(), a -= 2, redLeaf.pop();
            tree[x][0] = ++t, blackLeaf.push(t);
            tree[x][1] = ++t, blackLeaf.push(t);
        }
        if (f == 0) break;
    }
    if (a + b > 0) {
        cout << "No\n";
        return;
    }
    cout << "Yes\n";
    for (int i = 1; i <= n; i++) {
        for (auto j: tree[i])
            cout << j << " ";
        cout << "\n";
    }
    return;
}

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int TC;
    for (cin >> TC; TC; TC--)
        solve();
    return 0;
}

L-智乃的36倍数(easy version)

直接暴力枚举就好

#include<bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;
using i128 = __int128;
using ldb = long double;

#define int i64

using vi = vector<int>;

using pii = pair<int, int>;
using vii = vector<pii>;

const int inf = INT_MAX, INF = 1e18;
const int mod = 998244353;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
using edge = array<int, 3>;

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n;
    cin >> n;
    vi a(n);
    for( auto & i : a ) cin >> i;
    int res = 0;
    for( int i = 0 ; i < n ; i ++ )
        for( int j = 0 ; j < n ; j ++ ){
            if( i == j ) continue;
            if (a[j] < 10) {
                if ((a[i] * 10 + a[j]) % 36 == 0) res++;
            } else {
                if ((a[i] * 100 + a[j]) % 36 == 0) res++;
            }
        }
    cout << res << "\n";
    return 0;

}

M-智乃的36倍数(normal version)

因为数字位数有限,可以计算每个数字在某个位置下模 36 的值,然后枚举低位的值和低位占的位数,然后既可以计算出高位的值,这样就可以统计方案数。

#include<bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;
using i128 = __int128;
using ldb = long double;

#define int i64

using vi = vector<int>;

using pii = pair<int, int>;
using vii = vector<pii>;

const int inf = INT_MAX, INF = 1e18;
const int mod = 998244353;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
using edge = array<int, 3>;


i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n, res = 0;
    cin >> n;
    vector cntA(20, vi(36)), cntB(20, vi(36));

    for (int x, y; n; n--) {
        cin >> x, y = log10(x) + 1;

        cntA[y][x % 36]++;
        for (i128 i = 1, j = 10; i <= 19; i++, j *= 10)
            cntB[i][(i128(x) * j) % 36]++;

        i128 z = x;
        for (int i = 1; i <= y; i++) z = z * 10;
        z += x;
        if (z % 36 == 0) res--;
    }
    for (int i = 1; i <= 19; i++)
        for (int j = 0; j < 36; j++)
            res += cntA[i][j] * cntB[i][(36 - j) % 36];
    cout << res << "\n";
    return 0;
}
posted @ 2024-03-07 20:15  PHarr  阅读(12)  评论(0编辑  收藏  举报