2024牛客寒假算法基础集训营3
1|0A-智乃与瞩目狸猫、幸运水母、月宫龙虾
#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";
}
}
2|0B-智乃的数字手串
模二后,把序列按照连续相同进行分段,并且如果第一段和最后一段相同则要合并成一段,如果一共分成了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();
}
3|0C-智乃的前缀、后缀、回文
其实是是一个字符串模板题了算是,所以我用了两个字符串算法来求解。
首先用 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;
}
当然了,判断回文串也可以逆序哈希求解。
4|0D-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";
}
}
5|0G-智乃的比较函数(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;
}
6|0H-智乃的比较函数(normal version)
同 G
7|0J-智乃的相亲活动
其实可以分开算每个女生不选某个男生的概率,分别累乘就可以计算出一个男生不被所有女生选中期望,然后就可以算出被选男生的数量的期望。女生同理。
#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;
}
8|0k-智乃的“黑红树”
构造起来还算简单,简单思路就是用两个队列分别进行 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;
}
9|0L-智乃的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;
}
10|0M-智乃的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;
}
__EOF__

本文作者:PHarr
本文链接:https://www.cnblogs.com/PHarr/p/18059672.html
关于博主:前OIer,SMUer
版权声明:CC BY-NC 4.0
声援博主:如果这篇文章对您有帮助,不妨给我点个赞
本文链接:https://www.cnblogs.com/PHarr/p/18059672.html
关于博主:前OIer,SMUer
版权声明:CC BY-NC 4.0
声援博主:如果这篇文章对您有帮助,不妨给我点个赞
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
2023-03-07 SMU Spring 2023 Trial Contest Round 2