蓝桥杯2024C/C++省A(持续更新)
蓝桥杯2024C/C++省A(持续更新)
训练士兵
贪心
思路
将所有士兵按照训练次数从小到大排序(如果能团购的话团购的次数肯定是当前所有士兵次数的最小值)
当前训练此时所有士兵所有花费为\(sum\), 团购为\(s\),比较\(s\)与\(sum\)
-
\(s > sum\),不团购了,自己花钱训练
-
否则就选择团购
注意过程中要维护当前的\(sum\)和士兵训练次数
代码
神奇的代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
const int maxn = 2e5 + 5;
const int inf = 1e18;
struct custom_hash
{
static uint64_t splitmix64(uint64_t x)
{
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
return x;
}
size_t operator () (uint64_t x) const
{
static const uint64_t FIXED_RANDOM = std::chrono::steady_clock::now().time_since_epoch().count(); // 时间戳
return splitmix64(x + FIXED_RANDOM);
}
};
int a[maxn], b[maxn];
struct Node
{
int pri, cnt;
}node[maxn];
bool cmp(Node a, Node b)
{
return a.cnt < b.cnt;
}
void solve()
{
int n = 0, s = 0;
std::cin >> n >> s;
int sum = 0;
for (int i = 1; i <= n; i++)
{
std::cin >> node[i].pri >> node[i].cnt;
sum += node[i].pri;
}
std::sort(node + 1, node + 1 + n, cmp);
int ans = 0;
int cur = 0; // 团购的次数
for (int i = 1; i <= n; i++)
{
if (s < sum)
{
ans += s * (node[i].cnt - cur);
cur += (node[i].cnt- cur);
sum -= node[i].pri;
}
else
{
ans += node[i].pri * (node[i].cnt - cur);
sum -= node[i].pri;
}
}
std::cout << ans << endl;
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr); std::cout.tie(nullptr);
//freopen("out.txt", "w", stdout);
int t = 1;
//std::cin >> t;
while(t--)
{
solve();
}
return 0;
}
五子棋对弈
思路
有些像填数独
最难的部分还是判断,我们可以暴力判断每一行每一列和两条对角线,还要判断是否是轮流下棋,也就是一个下了\(13\)次,一个下了\(12\)次
检查次数
int cnt1 = 0, cnt2 = 0;
for (int i = 1; i <= 5; i++)
{
for (int j = 1; j <= 5; j++)
{
if (mat[i][j] == 1)
{
cnt1++;
}
else
{
cnt2++;
}
}
}
if (cnt1 - cnt2 != 1) return false;
检查每一行
// 检查每一行
for (int i = 1; i <= 5; i++)
{
bool flag = true;
for (int j = 1; j <= 5; j++)
{
if (mat[i][j] != mat[i][1])
{
flag = false;
break;
}
}
if (flag) return false;
}
检查每一列
// 检查每一列
for (int i = 1; i <= 5; i++)
{
bool flag = true;
for (int j = 1; j <= 5; j++)
{
if (mat[j][i] != mat[1][i])
{
flag = false;
break;
}
}
if (flag) return false;
}
检查对角线
// 检查对角线
// 主对角线 i == j
// 副对角线 i + j == 6
bool f1 = true;
for (int i = 1; i <= 5; i++)
{
if (mat[i][i] != mat[1][1])
{
f1 = false;
break;
}
}
if (f1) return false;
bool f2 = true;
for (int i = 1; i <= 5; i++)
{
if (mat[i][6 - i] != mat[1][5])
{
f2 = false;
break;
}
}
if (f2) return false;
return true;
以下代码耗时大约\(4s\)
神奇的代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
const int maxn = 2e5 + 5;
const int inf = 1e18;
struct custom_hash
{
static uint64_t splitmix64(uint64_t x)
{
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
return x;
}
size_t operator () (uint64_t x) const
{
static const uint64_t FIXED_RANDOM = std::chrono::steady_clock::now().time_since_epoch().count(); // 时间戳
return splitmix64(x + FIXED_RANDOM);
}
};
int mat[7][7];
bool check()
{
int cnt1 = 0, cnt2 = 0;
for (int i = 1; i <= 5; i++)
{
for (int j = 1; j <= 5; j++)
{
if (mat[i][j] == 1)
{
cnt1++;
}
else
{
cnt2++;
}
}
}
if (cnt1 - cnt2 != 1) return false;
// 检查每一行
for (int i = 1; i <= 5; i++)
{
bool flag = true;
for (int j = 1; j <= 5; j++)
{
if (mat[i][j] != mat[i][1])
{
flag = false;
break;
}
}
if (flag) return false;
}
// 检查每一列
for (int i = 1; i <= 5; i++)
{
bool flag = true;
for (int j = 1; j <= 5; j++)
{
if (mat[j][i] != mat[1][i])
{
flag = false;
break;
}
}
if (flag) return false;
}
// 检查对角线
// 主对角线 i == j
// 副对角线 i + j == 6
bool f1 = true;
for (int i = 1; i <= 5; i++)
{
if (mat[i][i] != mat[1][1])
{
f1 = false;
break;
}
}
if (f1) return false;
bool f2 = true;
for (int i = 1; i <= 5; i++)
{
if (mat[i][6 - i] != mat[1][5])
{
f2 = false;
break;
}
}
if (f2) return false;
return true;
}
int ans = 0;
void dfs(int x, int y)
{
if (y == 6) // 这一列走完了
{
dfs(x + 1, 1);
return;
}
if (x == 6) // 最后一行走完了
{
if (check()) ans++;
return;
}
mat[x][y] = 1;
dfs(x, y + 1);
mat[x][y] = 2;
dfs(x, y + 1);
mat[x][y] = 0;
}
void solve()
{
dfs(1, 1);
std::cout << ans << endl;
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr); std::cout.tie(nullptr);
//freopen("out.txt", "w", stdout);
int t = 1;
//std::cin >> t;
int s = clock();
while(t--)
{
solve();
}
int d = clock();
std::cout << d - s << endl;
return 0;
}
考虑剪枝优化
当\(cnt1\)和\(cnt2\)不符合条件时直接返回\(false\)
具体步骤为
- 在 \(dfs\) 函数中添加全局变量或传递参数来跟踪当前的 \(cnt1\) 和 \(cnt2\)。
- 计算剩余的单元格数。
- 判断是否有可能通过填充剩余单元格使得最终 \(cnt1 - cnt2 == 1\)。
- 如果不可能,立即返回,停止进一步的递归。
以下代码耗时约\(600ms\)
(其实复杂度并没有改变,仍为\(O(2^{25})\))
神奇的代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
const int maxn = 2e5 + 5;
const int inf = 1e18;
struct custom_hash
{
static uint64_t splitmix64(uint64_t x)
{
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
return x;
}
size_t operator () (uint64_t x) const
{
static const uint64_t FIXED_RANDOM = std::chrono::steady_clock::now().time_since_epoch().count(); // 时间戳
return splitmix64(x + FIXED_RANDOM);
}
};
int mat[7][7];
bool check()
{
// 检查每一行
for (int i = 1; i <= 5; i++)
{
bool flag = true;
for (int j = 1; j <= 5; j++)
{
if (mat[i][j] != mat[i][1])
{
flag = false;
break;
}
}
if (flag) return false;
}
// 检查每一列
for (int i = 1; i <= 5; i++)
{
bool flag = true;
for (int j = 1; j <= 5; j++)
{
if (mat[j][i] != mat[1][i])
{
flag = false;
break;
}
}
if (flag) return false;
}
// 检查对角线
// 主对角线 i == j
// 副对角线 i + j == 6
bool f1 = true;
for (int i = 1; i <= 5; i++)
{
if (mat[i][i] != mat[1][1])
{
f1 = false;
break;
}
}
if (f1) return false;
bool f2 = true;
for (int i = 1; i <= 5; i++)
{
if (mat[i][6 - i] != mat[1][5])
{
f2 = false;
break;
}
}
if (f2) return false;
return true;
}
int ans = 0;
void dfs(int x, int y, int c1, int c2)
{
if (y == 6)
{
dfs(x + 1, 1, c1, c2);
return;
}
if (x == 6)
{
if (c1 - c2 == 1 && check()) ans++;
return;
}
// 剩余的格子
int rest = 25 - 5 * (x - 1) - (y - 1) - 1;
mat[x][y] = 1;
if (c1 + 1 - c2 + rest >= 1)
{
dfs(x, y + 1, c1 + 1, c2);
}
mat[x][y] = 2;
if (c1 - (c2 + 1) + rest >= 1)
{
dfs(x, y + 1, c1, c2 + 1);
}
mat[x][y] = 0;
}
void solve()
{
dfs(1, 1, 0, 0);
std::cout << ans << endl;
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr); std::cout.tie(nullptr);
//freopen("out.txt", "w", stdout);
int t = 1;
//std::cin >> t;
//int s = clock();
while(t--)
{
solve();
}
//int d = clock();
//std::cout << d - s << endl;
return 0;
}
成绩统计
思路
让我们把式子拆开看一看
\(\sigma^2=\dfrac {\sum_{i=1}^k(v_i-\bar v)^2} k\)
设\(S_k\)为这\(k\)个数的和
\(\sum_{i = 1}^k(v_i - v)^2 = \sum_{i = 1}^k({v_i}^2 + \bar v^2 - 2\bar v{v_i}) = \sum_{i = 1}^k {v_i}^2 + k{\bar v}^2 - 2\bar v\sum_{i = 1}^k{v_i} = \sum_{i = 1}^k{v_i}^2 - \frac{{S_k}^2}{k}\)
我们只需要维护一个前缀平方和和一个前缀和就好了
找\(x\)就用二分查找就好了
时间复杂度\(O(n)\)
代码
神奇的代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
using ld = long double;
const int maxn = 2e5 + 5;
const int inf = 1e10;
const ld eps = 1e-15;
struct custom_hash
{
static uint64_t splitmix64(uint64_t x)
{
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
return x;
}
size_t operator () (uint64_t x) const
{
static const uint64_t FIXED_RANDOM = std::chrono::steady_clock::now().time_since_epoch().count(); // 时间戳
return splitmix64(x + FIXED_RANDOM);
}
};
inline int read()
{
int x = 0, flag = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if (ch == '-')
{
flag = -1;
}
ch = getchar();
}
while (ch <= '9' && ch >= '0')
{
x = x * 10 + ch - '0';
ch = getchar();
}
return x * flag;
}
int n = 0, k = 0;
int T = 0;
bool check(std::vector<int> nums, int pos)
{
if (pos < k) return false;
std::sort(nums.begin() + 1, nums.begin() + 1 + pos);
std::vector<int> pre(pos + 1, 0), pre2(pos + 1, 0);
for (int i = 1; i <= pos; i++)
{
pre[i] = pre[i - 1] + nums[i] * nums[i];
pre2[i] = pre2[i - 1] + nums[i];
}
for (int i = 1; i + k - 1 <= pos; i++)
{
ld t = (ld)(pre[i + k - 1] - pre[i - 1]);
ld s = (ld)(pre2[i + k - 1] - pre2[i - 1]);
ld t2 = (ld)(s * s) / (ld)k;
if ((ld)k * T - (t - t2) > eps) return true;
}
return false;
}
void solve()
{
std::cin >> n >> k >> T;
std::vector<int> nums(n + 1, 0);
for (int i = 1; i <= n; i++)
{
std::cin >> nums[i];
}
int l = 0, r = n + 1;
while(l + 1 < r)
{
int mid = (l + r) >> 1;
if (check(nums, mid))
{
r = mid;
}
else
{
l = mid;
}
}
if (r == n + 1)
{
printf("%d", -1);
}
else
{
printf("%lld", r);
}
}
signed main()
{
//freopen("out.txt", "w", stdout);
int t = 1;
// t = read();
//int s = clock();
while(t--)
{
solve();
}
//int d = clock();
//std::cout << d - s << endl;
return 0;
}

浙公网安备 33010602011771号