The 2024 CCPC Online Contest
B - 军训 II#
题意#
n个人,第i个人身高为
,定义不整齐度为所有区间的身高极差之和。求不整齐度的最小值以及现在的排列方案数。
不整齐度:
思路#
按身高排序,此时不整齐度最小。身高相同的人可以换位置,k个身高相同的人可以有
种排列,将所有身高的排列数相乘后,再判断是否所有人身高都相同,否则可以有升序降序两种排序,额外乘2。(注意 的情况,在这里WA了一发😭)
代码#
点击查看代码
#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353;
void solve()
{
int n;
scanf("%lld", &n);
vector<int> v(n);
for (int i = 0; i < n; i++)
{
scanf("%lld", &v[i]);
}
if (n == 1) // 特判
{
printf("0 1");
return;
}
sort(v.begin(), v.end());
vector<vector<int>> maxn(n, vector<int>(n, 0)), minn(n, vector<int>(n, 1e6 + 1)); // minn[i][j]表示区间[i, j]的最小值
int sum = 0; // 最小不整齐度
for (int l = 0; l < n; l++)
{
maxn[l][l] = minn[l][l] = v[l];
for (int r = l + 1; r < n; r++)
{
maxn[l][r] = max(maxn[l][r - 1], v[r]);
minn[l][r] = min(minn[l][r - 1], v[r]);
sum += maxn[l][r] - minn[l][r];
}
}
// 全排列预处理
vector<int> A(n + 1);
A[1] = 1;
for (int i = 2; i <= n; i++)
{
A[i] = (A[i - 1] * i) % mod;
}
int ans = 1, k = 1; // 排列数(暂时认为升序降序两种),相邻重复数(至少有自己一个)
bool f = false;
for (int i = 1; i < n; i++)
{
if (v[i] == v[i - 1])
{
k++;
if (k == n) // 全相同则升序降序排列相同
{
f = true;
}
}
else
{
ans = (ans * A[k]) % mod;
k = 1; // 重置
}
}
if (k > 1) // 处理最后相同的部分
{
ans = (ans * A[k]) % mod;
}
if (!f)
{
ans = (ans * 2) % mod;
}
printf("%lld %lld", sum, ans);
}
signed main()
{
int T = 1;
//scanf("%d", &T);
while (T--)
{
solve();
}
return 0;
}
D - 编码器-解码器#
题意#
思路#
区间dp,贴个fzb的码
代码#
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mxn = 1e2 + 5;
const int mod = 998244353;
int dp[mxn][mxn][mxn];
void solve()
{
string s, t;
cin >> s >> t;
int n = s.size();
int m = t.size();
s = " " + s;
t = " " + t;
for (int i = 1; i <= m; i++)
{
dp[1][i][i] = (s[1] == t[i]);
}
for (int i = 2; i <= n; i++)
{
for (int len = 1; len <= m; len++)
{
if (len == 1)
{
for (int j = 1; j <= m; j++)
{
dp[i][j][j] = (2 * dp[i - 1][j][j] % mod + (s[i] == t[j])) % mod;
}
continue;
}
for (int l = 1; l + len - 1 <= m; ++l)
{
int r = l + len - 1;
dp[i][l][r] = 2 * dp[i - 1][l][r] % mod;
dp[i][l][r] %= mod;
for (int k = l; k < r; ++k)
{
dp[i][l][r] += dp[i - 1][l][k] * dp[i - 1][k + 1][r] % mod;
dp[i][l][r] %= mod;
}
for (int k = l; k <= r; ++k)
{
if (t[k] == s[i])
{
if (k == l)
{
dp[i][l][r] += dp[i - 1][k + 1][r];
}
else if (k == r)
{
dp[i][l][r] += dp[i - 1][l][k - 1];
}
else
{
dp[i][l][r] += dp[i - 1][l][k - 1] * dp[i - 1][k + 1][r] % mod;
}
dp[i][l][r] %= mod;
}
}
}
}
}
cout << dp[n][1][m] << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
//cin >> T;
while (T--)
{
solve();
}
return 0;
}
E - 随机过程#
题意#
个长度为 的字符串,其每个字符是从 到 的字母等概率随机选择的。将这些字符串插入字典树,求最多节点数以及期望节点数,对结果取模 ,且期望节点数需要输出其分数形式的逆元。
思路#
对于最大节点数,考虑贪心。考虑深度为
的节点最多能有多少个。那么如果 ,贡献为 ;否则贡献为 。
对于期望节点数,显然每一层中所有节点出现在 Trie 中的期望是一样的。考虑计算第层某个特定点出现的概率,然后最后乘上总个数并求和即可。对于第 层某个节点,其不出现的概率为 。因此答案为:
代码#
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353;
int qpow(int base, int x)
{
int res = 1;
while (x)
{
if (x & 1)
{
res *= base;
res %= mod;
}
x >>= 1;
base *= base;
base %= mod;
}
return res;
}
void solve()
{
int n, m;
cin >> n >> m;
int maxn = 0, ans = 0;
for (int i = 0; i <= m; i++)
{
maxn += (i <= 3 && qpow(26, i) <= n ? qpow(26, i) : n);
maxn %= mod;
}
for (int i = 0; i <= m; i++)
{
ans += (1 - (qpow(1 - qpow(qpow(26, i), mod - 2), n))) % mod * qpow(26, i) % mod;
ans = (ans + mod) % mod; // 调为正数
}
cout << maxn << " " << ans << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
//cin >> T;
while (T--)
{
solve();
}
return 0;
}
J - 找最小#
题意#
给两个长为
的序列 、 ,可以交换两序列中对应位置的数,并且可以操作任意次。输出无趣度最小时,无趣度大的那个序列,即输出最小的 。
无趣度:。
思路#
可以观察到,如果当前两个数组的异或和分别是
、 ,则交换 、 的操作等价于 、 ,所以用 构造线性基。求出两序列的异或和 、 ,从高位往低位找,对于第 位:若都是 ,且线性基这一位 有值,则 、 同时异或 ,把这位变成 (尽可能化小);两个 就不处理下一位;剩下的情况只需要将较大的一方的这位化为 即可。
代码#
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int base[32];
void insert(int x)
{
for (int i = 30; i >= 0; i--)
{
if (x & (1LL << i))
{
if (!base[i])
{
base[i] = x;
return;
}
x ^= base[i];
}
}
}
void solve()
{
int n;
cin >> n;
fill(base, base + 32, 0);
int A = 0, B = 0;
vector<int> a(n), b(n);
for (int i = 0; i < n; i++)
{
cin >> a[i];
A ^= a[i];
}
for (int i = 0; i < n; i++)
{
cin >> b[i];
B ^= b[i];
insert(a[i] ^ b[i]);
}
int ans = max(A, B);
for (int i = 30; i >= 0; i--)
{
if (!(A >> i & 1) && !(B >> i & 1)) // 两个0
{
continue;
}
if (A < B)
{
swap(A, B);
}
if (A >> i & 1)
{
A ^= base[i];
B ^= base[i];
}
}
ans = min(ans, max(A, B));
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
//cin >> T;
while (T--)
{
solve();
}
return 0;
}
K - 取沙子游戏#
题意#
n粒沙子,Alice与Bob轮流取沙子(Alice先手),要求要求取的数量不能超过 k,且必须为前面所有取的沙子数量的公因数(包括对手的)。Alice第一次取沙子时,沙子个数不受第二条限制,即不超过 k 即可。先取完的获胜。两人都绝对聪明。问谁赢。
思路#
首先如果k
n,先手可以直接拿走所有沙子,先手必胜。那么我们要找的是对于给定n,先手必胜所需k的最小值,从最小的1开始考虑,局面为1的奇数倍时必胜,必败时k增加到最小的必败情况,即1的最小偶数倍(2倍),即k=2,此时2的奇数倍必胜,否则k=2,第n轮由于 的因数都是已经考虑过的情况,两人都不会选,所以每次循环两人都只会取k个沙子,判断过程和第一轮是一样的,所以可以每轮n/=2转化为第一轮的情况,t=2记录k的最小值。
代码#
点击查看代码
#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
void solve()
{
int n, k;
scanf("%d%d", &n, &k);
if (k >= n)
{
printf("Alice\n");
return;
}
long long t = 1;
while (true)
{
if (n & 1)
{
printf("Alice\n");
return;
}
n /= 2;
t *= 2;
if (t > k)
{
printf("Bob\n");
return;
}
}
}
signed main()
{
int T = 1;
scanf("%d", &T);
while (T--)
{
solve();
}
return 0;
}
L - 网络预选赛#
题意#
给定(n * m)的矩阵,求其(2 * 2)子矩阵左到右,上到下是"ccpc"的数量。
思路#
遍历每个元素作为子矩阵的左上角,再一次检查其他角即可。
代码#
点击查看代码
#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
char mp[505][505];
void solve()
{
int n, m;
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++)
{
scanf("%s", &mp[i]);
}
int ans = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (mp[i][j] == 'c' && mp[i][j + 1] == 'c' && mp[i + 1][j] == 'p' && mp[i + 1][j + 1] == 'c')
{
ans++;
}
}
}
printf("%d", ans);
}
signed main()
{
int T = 1;
//scanf("%d", &T);
while (T--)
{
solve();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】