2023 年 4 月 8 日是蓝桥杯省赛,今年我参加的是 C++ 组 B 组,虽然说打得不是很理想,不过好在个人感觉省一问题不是很大,反正只要是省一对得多对得少都一样。
比赛中的代码是没法保存的,所以我借着新鲜的记忆,重新把我会写的题的代码都码了一遍,只是过了样例,不能保证是正确答案,不过思路大差不差,应该还是具有借鉴价值的吧。
235
#include
const int n = 100;
bool check(std::string &s, std::string &t) {
int j = 0;
for (int i = 0; i < n; i++) {
if (j < (int) t.size() && s[i] == t[j]) {
j++;
}
}
if (j == t.size())
return true;
return false;
};
int main() {
std::string s = "5686916124919823647759503875815861830379270588570991944686338516346707827689565614010094809128502533";
int ans = 0;
std::string year = "2023";
int d[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
for (int i = 1; i <= 12; i++) {
std::string month = std::to_string(i);
if (month.size() == 1) {
month = "0" + month;
}
for (int j = 1; j <= d[i]; j++) {
std::string day = std::to_string(j);
if (day.size() == 1) {
day = "0" + day;
}
std::string t = year + month + day;
if (check(s, t)) {
ans++;
}
}
}
std::cout << ans;
return 0;
}
11027421
#include "bits/stdc++.h"
double eps = 1E-4;
double get(int x, int y)
{
double zero = 1.0 * x / (1.0 * (x + y));
double one = 1.0 * y / (1.0 * (x + y));
return -(x * zero * log2(zero) + y * one * log2(one));
}
int main() {
int n = 23333333;
for (int i = 0; i <= n; i++) {
if (abs(get(i, n - i) - 11625907.5798) <= eps) {
std::cout << i << '\n';
return 0;
}
}
return 0;
}
#include
#include
#define int long long
const int N = 1e4 + 1;
std::pair a[N];
signed main()
{
int n;
std::cin >> n;
int mx = INT_MAX;
for (int i = 0; i < n; i ++) {
std::cin >> a[i].first >> a[i].second;
mx = std::min(mx, a[i].first / a[i].second);
}
int l = 1, r = 2e9, mn = r;
while(l <= r) {
int mid = (l + r) >> 1;
bool ok = 1;
for (int i = 0; i < n; i ++) {
if(a[i].first / mid > a[i].second) {
ok = 0;
break;
}
}
if(ok) {
mn = mid;
r = mid - 1;
}
else l = mid + 1;
}
std::cout << mn << ' ' << mx;
return 0;
}
对于这种签到题,二分未免有点过于小题大做了,直接贪心即可
#include
#include
#define int long long
signed main()
{
int n;
std::cin >> n;
int mx = INT_MAX, mn = 0;
for (int i = 0; i < n; i ++) {
int a, b;
std::cin >> a >> b;
mx = std::min(mx, a / b);
mn = std::max(mn, a / (b + 1) + 1);
}
std::cout << mn << ' ' << mx;
return 0;
}
听说这题可以用状压DP,不过我这种菜鸡显然只会全排列无脑暴力。毕竟复杂度也在允许范围内嘛~
复杂度 .
#include
#include
struct node {
int l, r, len;
};
node a[11];
int idx[11]; //存放下标的数组,便于全排列
void solve()
{
int n;
std::cin >> n;
for (int i = 1; i <= n; i ++) {
std::cin >> a[i].l >> a[i].r >> a[i].len;
a[i].r += a[i].l;
}
for (int i = 1; i <= n; i ++)
idx[i] = i;
do {
int rs = a[idx[1]].l + a[idx[1]].len;
bool ok = 1;
for (int k = 2; k <= n; k ++) {
int i = idx[k];
if(a[i].r < rs) {
ok = 0;
break;
}
rs = std::max(rs, a[i].l) + a[i].len;
}
if(ok) {
std::cout << "YES\n";
return;
}
}while(std::next_permutation(idx + 1, idx + n + 1));
std::cout << "NO\n";
}
signed main()
{
int t = 1;
std::cin >> t;
while(t --) {
solve();
}
return 0;
}
这题很明显是需要DP的,正常的写法是复杂度 ,可以过前 50% 的数据点。
#include
#include
#include
const int N = 1e5 + 1;
int dp[N];
signed main()
{
int n;
std::cin >> n;
std::vector a(n + 1);
for (int i = 1; i <= n; i ++) {
std::cin >> a[i];
dp[i] = 1;
for (int j = 1; j < i; j ++) {
if(a[i].front() == a[j].back()) {
dp[i] = std::max(dp[i], dp[j] + 1);
}
}
}
int ans = 0;
for (int i = 1; i <= n; i ++) {
ans = std::max(ans, dp[i]);
}
std::cout << n - ans;
return 0;
}
我们可以将其优化至 复杂度,就可以过 100% 的数据点了
#include
#include
#include
const int N = 1e5 + 1;
int dp[N];
int pre[11];
signed main()
{
memset(pre, -1, sizeof(pre));
int n;
std::cin >> n;
std::vector a(n + 1);
for (int i = 1; i <= n; i ++) {
std::cin >> a[i];
}
int ans = 0;
for (int i = 1; i <= n; i ++) {
int x = a[i].front() - '0';
int y = a[i].back() - '0';
if (pre[x] != -1)
dp[i] = dp[pre[x]] + 1;
else
dp[i] = 1;
ans = std::max(ans, dp[i]);
if (pre[y] == -1)
pre[y] = i;
else if(dp[i] > dp[pre[y]])
pre[y] = i;
}
std::cout << n - ans;
return 0;
}
在最外面加一圈 0 ,然后从左上角开始往 8 个方向搜索0,形成的空洞,搜索空洞数量即可。
复杂度 .
#include
#include
#include
#include
const int N = 55, black = -1; //用-1代表染黑的地方
int g[N][N], g2[N][N], st[N][N];
int dx[] = {1, 0, -1, 0, 1, 1, -1, -1}, dy[] = {0, 1, 0, -1, 1, -1, 1, -1};
int n, m;
int cur; //记录某个岛屿的编号
void color(int I, int J)
{
std::queue > q;
q.push({I, J});
st[I][J] = 1;
g2[I][J] = black;
while(q.size()) {
int x = q.front().first, y = q.front().second;
q.pop();
for (int i = 0; i < 8; i ++) {
int xx = x + dx[i], yy = y + dy[i];
if(0 <= xx && xx <= n + 1 && 0 <= yy && yy <= m + 1 &&
g[xx][yy] == 0 && st[xx][yy] == 0) {
st[xx][yy] = 1;
g2[xx][yy] = black;
q.push({xx, yy});
}
}
}
}
void bfs(int I, int J)
{
std::queue > q;
q.push({I, J});
st[I][J] = 1;
g2[I][J] = cur;
while(q.size()) {
int x = q.front().first, y = q.front().second;
q.pop();
for (int i = 0; i < 4; i ++) {
int xx = x + dx[i], yy = y + dy[i];
if(0 <= xx && xx <= n + 1 && 0 <= yy && yy <= m + 1 &&
g2[xx][yy] == 0 && st[xx][yy] == 0) {
st[xx][yy] = 1;
g2[xx][yy] = cur;
q.push({xx, yy});
}
}
}
}
void solve()
{
memset(g, 0, sizeof(g));
memset(g2, 0, sizeof(g2));
memset(st, 0, sizeof(st));
std::cin >> n >> m;
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= m; j ++) {
char x;
std::cin >> x;
g[i][j] = x - '0';
}
}
color(0, 0);
cur = 0;
for (int i = 0; i <= n + 1; i ++) {
for (int j = 0; j <= m + 1; j ++) {
if(g2[i][j] == 0) {
cur++;
bfs(i, j);
}
}
}
std::cout << cur << '\n';
}
signed main()
{
int t = 1;
std::cin >> t;
while(t --) {
solve();
}
return 0;
}
算是一个简单的签到题,直接存储下标,然后二分就行了,复杂度 。
#include
#include
#include
#include
#define int long long
signed main()
{
int k;
std::cin >> k;
std::string s;
std::cin >> s;
char c1, c2;
std::cin >> c1 >> c2;
int n = s.size();
std::vector a1, a2;
for (int i = 0; i < n; i ++) {
if(s[i] == c1)
a1.push_back(i + 1);
if(s[i] == c2)
a2.push_back(i + 1);
}
int ans = 0;
for (size_t i = 0; i < a1.size(); i ++) {
if(a2.size() == 0)
continue;
int loc = std::lower_bound(a2.begin(), a2.end(), a1[i] + k - 1) - a2.begin();
ans += (int)a2.size() - loc;
}
std::cout << ans;
return 0;
}
这题比赛中只写出个暴力,也就是说只能过掉前 20% 的数据。不过这题其实是会写的,只不过赛中时间不是很多,就先打了个暴力做后面的去了(
解法:
#include
#include
#include
const int N = 5e5 + 1;
int a[N];
signed main()
{
int n, k;
std::cin >> n >> k;
for (int i = 1; i <= n; i ++) {
std::cin >> a[i];
}
for (int i = 1; i <= k; i ++) {
int loc = std::min_element(a + 1, a + n + 1) - a;
a[loc - 1] += a[loc];
a[loc + 1] += a[loc];
for (int j = loc; j < n; j ++) {
a[j] = a[j + 1];
}
--n;
}
for (int i = 1; i <= n; i ++)
std::cout << a[i] << ' ';
return 0;
}
优先队列解法 :
#include "bits/stdc++.h"
using ll = long long;
std::priority_queue,
std::vector>, std::greater>> q;
int main() {
int n, k;
std::cin >> n >> k;
std::vector a(n);
for (int i = 0; i < n; i++) {
std::cin >> a[i];
}
for (int i = 0; i < n; i++) {
q.push({a[i], i});
}
std::vector pre(n), nex(n);
std::iota(pre.begin(), pre.end(), -1);
std::iota(nex.begin(), nex.end(), 1);
while (q.size()) {
auto Top = q.top();
ll ai = Top.first;
int i = Top.second;
q.pop();
if (ai != a[i]) {
q.push({a[i], i});
continue;
}
a[i] = -1;
int Nex = nex[i];
int Pre = pre[i];
if (Nex < n) {
a[Nex] += ai;
pre[Nex] = Pre;
}
if (Pre >= 0) {
a[Pre] += ai;
nex[Pre] = Nex;
}
k--;
if (k == 0) {
break;
}
}
for (int i = 0; i < n; i++) {
if(a[i] != -1)
std::cout << a[i] << ' ';
}
return 0;
}
这题看似很难,其实是比较简单的算法题,需要用到 LCA 算法,比赛中我码了 40 多分钟,不过好在过了样例,没有出现 bug ,也是让我舒了一口气。
复杂度 .
#include
#include
#include
#define int long long
int n, k;
const int N = 1e5 + 5, M = 2e5 + 5;
int f[N][20], d[N][20];
int a[N], dep[N];
int d1[N], d2[N];
int h[N], ne[M], e[M], w[M], idx;
void add(int a, int b, int c)
{
e[idx] = b; w[idx] = c; ne[idx] = h[a]; h[a] = idx++;
}
void dfs(int cur, int pre, int dis)
{
dep[cur] = dep[pre] + 1;
f[cur][0] = pre;
d[cur][0] = dis;
for (int i = 1; i <= std::__lg(dep[cur]); i++) {
f[cur][i] = f[f[cur][i - 1]][i - 1];
d[cur][i] = d[cur][i - 1] + d[f[cur][i - 1]][i - 1];
}
for (int i = h[cur]; i != -1; i = ne[i]) {
int x = e[i];
if (x == pre)
continue;
dfs(x, cur, w[i]);
}
}
int lca(int u, int v)
{
if (dep[u] < dep[v]) {
std::swap(u, v);
}
int ans = 0;
for (int i = (int) std::__lg(dep[u] - dep[v]); i >= 0; i--) {
if (dep[f[u][i]] >= dep[v]) {
ans += d[u][i];
u = f[u][i];
}
}
if (u == v)
return ans;
for (int i = (int) std::__lg(dep[u]); i >= 0; i--) {
if (f[u][i] != f[v][i]) {
ans += d[u][i];
ans += d[v][i];
u = f[u][i];
v = f[v][i];
}
}
return ans + d[u][0] + d[v][0];
}
signed main()
{
memset(h, -1, sizeof(h));
std::cin >> n >> k;
for (int i = 1; i < n; i ++) {
int u, v, w;
std::cin >> u >> v >> w;
add(u, v, w);
add(v, u, w);
}
for (int i = 1; i <= k; i ++)
std::cin >> a[i];
dfs(1, 0, 0);
int p1 = 0, p2 = 0;
for (int i = 2; i <= k; i ++) {
d1[p1++] = lca(a[i], a[i - 1]);
if(i != 2)
d2[p2++] = lca(a[i], a[i - 2]);
}
int sum = 0;
for (int i = 0; i < p1; i++)
sum += d1[i];
for (int i = 1; i <= k; i ++) {
int ans = 0;
if(i == 1)
ans = sum - d1[i - 1];
else if(i == k)
ans = sum - d1[i - 2];
else ans = sum - d1[i - 1] - d1[i - 2];
if(i != 1 && i != k) {
ans += d2[i - 2];
}
std::cout << ans << ' ';
}
return 0;
}
这一题赛中已经没时间了(当时只剩20分钟了),所以就写了个 的暴力(其实哪怕有时间也估计做不出来了)。
#include
#include
const int N = 1e5 + 1;
int f[N];
std::pair a[N], b[N];
int find(int x)
{
if(x != f[x])
f[x] = find(f[x]);
return f[x];
}
signed main()
{
int n, m;
std::cin >> n >> m;
for (int i = 1; i < n; i++) {
int x, y;
std::cin >> x >> y;
a[i] = {x, y};
}
for (int i = 1; i <= m; i ++) {
int x, y;
std::cin >> x >> y;
b[i] = {x, y};
}
for (int i = n - 1; i >= 1; i --) {
for (int j = 1; j <= n; j ++)
f[j] = j;
for (int j = 1; j < n; j ++) {
if(i == j)
continue;
int l = a[j].first, r = a[j].second;
l = find(l), r = find(r);
if(l != r)
f[l] = r;
}
bool ok = 1;
for (int j = 1; j <= m; j ++) {
int l = b[j].first, r = b[j].second;
l = find(l), r = find(r);
if(l == r) {
ok = 0;
break;
}
}
if(ok) {
std::cout << i << '\n';
return 0;
}
}
std::cout << -1;
return 0;
}
正解的话可以用 LCA + 树上差分,处理出每条树上边被 路径经过的次数,最大的被经过 m 次的边就是答案。
复杂度 .
#include
#include
#include
#include
//#define int long long
int n, m;
const int N = 1e5 + 5, M = 2e5 + 5;
int f[N][20];
int dep[N], d[N];
int h[N], ne[M], e[M], idx;
void add(int a, int b)
{
e[idx] = b; ne[idx] = h[a]; h[a] = idx++;
}
void dfs(int cur, int pre)
{
dep[cur] = dep[pre] + 1;
f[cur][0] = pre;
for (int i = 1; i <= std::__lg(dep[cur]); i++) {
f[cur][i] = f[f[cur][i - 1]][i - 1];
}
for (int i = h[cur]; i != -1; i = ne[i]) {
int next = e[i];
if (next == pre)
continue;
dfs(next, cur);
}
}
int lca(int u, int v)
{
if (dep[u] < dep[v])
std::swap(u, v);
for (int i = (int) std::__lg(dep[u] - dep[v]); i >= 0; i--) {
if (dep[f[u][i]] >= dep[v]) {
u = f[u][i];
}
}
if (u == v)
return u;
for (int i = (int) std::__lg(dep[u]); i >= 0; i--) {
if (f[u][i] != f[v][i]) {
u = f[u][i];
v = f[v][i];
}
}
return f[u][0];
}
void dfs2(int cur, int pre) {
for (int i = h[cur]; i != -1; i = ne[i]) {
int next = e[i];
if (next != pre) {
dfs2(next, cur);
d[cur] += d[next];
}
}
}
signed main()
{
memset(h, -1, sizeof(h));
std::cin >> n >> m;
std::vector > edge(n);
for (int i = 1; i < n; i ++) {
std::cin >> edge[i].first >> edge[i].second;
edge[i] = {edge[i].first, edge[i].second};
add(edge[i].first, edge[i].second);
add(edge[i].second, edge[i].first);
}
dfs(1, 0);
for (int i = 1; i <= m; i ++) {
int a, b;
std::cin >> a >> b;
int fa = lca(a, b);
d[a]++, d[b]++;
d[fa]--;
d[f[fa][0]]--;
}
dfs2(1, 0);
for (int i = n - 1; i >= 1; i --) {
if(d[edge[i].first] == m && d[edge[i].second] == m) {
std::cout << i;
return 0;
}
}
std::cout << -1;
return 0;
}
日后有时间更新正解~