2025牛客寒假算法基础集训营第四场补题

比赛主页

E-Tokitsukaze and Dragon's Breath

原题:E-Tokitsukaze and Dragon's Breath

题意:

寻找矩阵中的一个点,使得这个点向左上、右上、左下、右下四个方向延伸出的 "X" 型的权值累加和最大,输出最大值。

思路:

对于 "X" 型,可以分成往左倾斜、往右倾斜。

  • 往左倾斜: i - j 相等
  • 往右倾斜: i + j 相等

分别记录两种对角线的每一条对角线的权值累加和,然后遍历矩阵每一个点,取最大。

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MOD = 1e9 + 7;

int t, n, m;
//      向右倾斜的对角线 i+j 都相等
//      向左倾斜的对角线 i-j 都相等
void solve()
{
    cin >> n >> m;
    vector<vector<int>> v(n + 1, vector<int>(m + 1));
    map<int, int> mp1, mp2;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cin >> v[i][j];
            mp1[i + j] += v[i][j];
            mp2[i - j] += v[i][j];
        }
    }
    int ans = 0;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            ans = max(ans, mp1[i + j] + mp2[i - j] - v[i][j]);
        }
    }
    cout << ans << "\n";
}

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

/*
1
6 9
0 0 1 0 0 0 0 0 1
0 0 0 1 0 0 0 1 0
0 0 0 0 1 0 1 0 0
0 0 0 0 0 1 0 0 0
0 0 0 0 1 0 1 0 0
0 0 0 1 0 0 0 1 0
*/

C-Tokitsukaze and Balance String (hard)

原题:C-Tokitsukaze and Balance String (hard)

题意:

给定一个由 '0'、'1'、'?' 组成的字符串,其中 '?' 可以是 '0',也可以是 '1',问其中有多少个位置的字符经过取反后,使得该字符串中的 "10"子串 与 "01" 子串的数量相等(数量相等的情况定义为平衡)。如果其中 '?' 个数为 p,那么可以有 2^p 种情况。

思路:

  • 首尾字符相同,那么必定平衡,那么取反后使得字符串是平衡的位置共有 n-2 个(除了首尾)
  • 首位字符不同,那么必不平衡,那么取反后使得字符串是平衡的位置共有 2 个(首尾)
  • 字符串只有一个字符
  • 首尾都不是 '?'
  • 首尾都是 '?'
  • 首尾有一个 '?'
//      https://ac.nowcoder.com/acm/contest/95336/C
//      1:首尾相同,就是平衡
//      2:首位不同,就不平衡

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MOD = 1e9 + 7;

int t, n, m;
int fastpow(int a, int x)
{
    int res = 1;
    while (x)
    {
        if (x & 1)
            res = (res * a) % MOD;
        a = (a * a) % MOD;
        x >>= 1;
    }
    return res;
}
void solve()
{
    string s;
    cin >> n, cin >> s;
    if (n == 1) // 只有一个字符
    {
        cout << (s[0] == '?' ? 2 : 1) << "\n";
        return;
    }
    int cnt = 0, ans = 0;
    for (int i = 0; i < n; i++)
        if (s[i] == '?')
            cnt++;
    if (s[0] != '?' && s[n - 1] != '?') // 首尾都不是 '?'
    {
        if (s[0] == s[n - 1])
            ans = ((n - 2) * fastpow(2, cnt)) % MOD;
        else
            ans = (2 * fastpow(2, cnt)) % MOD;
    }
    else if (s[0] == '?' && s[n - 1] == '?') // 首尾都是 '?'
        ans = (2 * n * fastpow(2, cnt - 2)) % MOD;
    else // 首尾只有一个 '?'
        ans = (n * fastpow(2, cnt - 1)) % MOD;
    cout << ans << "\n";
}

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

D-Tokitsukaze and Concatenate‌ Palindrome

原题:Tokitsukaze and Concatenate‌ Palindrome

题意:

给定两个字符串 a, b,可以对这两个字符串进行重新排列,然后也可以选择一个字符串,再从这个字符串中选一个字符,替换为 26 个字母中的任意一个,最后将这两个字符串首尾相接成 str = a + b,使得字符串 str 是回文。问最少的选择替换次数是多少?

思路:

  • 先去掉两个字符串的所有公共字母,那么剩下的两个字符集合里面就相互没有公共字符了;
  • 设短的字符串还剩下 cntb 个字符,再用 cnta 表示长的字符串经过去重后还有奇数个的字母的数量
  • cntb >= cnta,则 ans = cntb
  • cntb < cnta,则 ans = cntb + (cnta-cntb)/2

为什么呢?

设长的字符串为 a,短的字符串为 b,去重后的短的字符串是一定要进行替换的,因为它可能与去重后的长的字符串形成回文,然后用 a 中的奇数数量的字母去跟 b 的字符匹配,如果 cnta 不够,那么只能用偶数数量的字母了,就是 (cnta-cntb) / 2 。


//      https://ac.nowcoder.com/acm/contest/95336/D

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MOD = 1e9 + 7;

int t, n, m;
void solve()
{
    string s, t;
    cin >> n >> m;
    cin >> s >> t;
    if (n < m)
        swap(s, t), swap(n, m);
    map<char, int> mps, mpt;
    for (int i = 0; i < n; i++)
        mps[s[i]]++;
    for (int i = 0; i < m; i++)
        mpt[t[i]]++;
    for (int i = 0; i < 26; i++)
    {
        if (mps['a' + i] != 0 && mpt['a' + i] != 0)
        {
            int temp = min(mps['a' + i], mpt['a' + i]);
            mps['a' + i] -= temp, mpt['a' + i] -= temp;
            n -= temp, m -= temp;
        }
    }
    int cnta = 0, cntb = m;
    for (int i = 0; i < 26; i++)
    {
        if (mps['a' + i] % 2 != 0)
            cnta++;
    }
    int ans = (cntb >= cnta ? cntb : (cntb + (cnta - cntb) / 2));
    cout << ans << "\n";
}

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

posted @ 2025-02-21 23:44  明天天晴KKK  阅读(10)  评论(0)    收藏  举报