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;
}