蓝桥杯2023年第十四届省赛真题题解

日期统计

纯暴力 + 剪枝(注意日期年月日的一些特性)

#include <iostream>
#include <unordered_set>
using namespace std;
const int nums[] = {0, 5, 6, 8, 6, 9, 1, 6, 1, 2, 4, 9, 1, 9, 8, 2, 3, 6, 4, 7, 7, 5, 9, 5, 0, 3, 8, 7, 5, 8, 1, 5, 8, 6, 1, 8, 3, 0, 3, 7, 9, 2, 7, 0, 5, 8, 8, 5, 7, 0, 9, 9, 1, 9, 4, 4, 6, 8, 6, 3, 3, 8, 5, 1, 6, 3, 4, 6, 7, 0, 7, 8, 2, 7, 6, 8, 9, 5, 6, 5, 6, 1, 4, 0, 1,
    0, 0, 9, 4, 8, 0, 9, 1, 2, 8, 5, 0, 2, 5, 3, 3};
const int n = 100;
const int days[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
unordered_set<string> st;
int main(int argc, const char * argv[]) {
    int sum = 0;
    for (int a = 1; a <= n; ++a) {//year
        if (nums[a] == 2) {
            for (int b = a + 1; b <= n; ++b) //year
                if (nums[b] == 0) {
                    for (int c = b + 1; c <= n; ++c) {//year
                        if (nums[c] == 2) {
                            for (int d = c + 1; d <= n; ++d) {//year
                                if (nums[d] == 3) {
                                    for (int e = d + 1; e <= n; ++e) {//month
                                        if (nums[e] == 0 || nums[e] == 1) {
                                            for (int f = e + 1; f <= n; ++f) {//month
                                                if ((nums[e] == 0 && nums[f] != 0) || (nums[e] == 1 && nums[f] <= 2)) {
                                                    for (int g = f + 1; g <= n; ++g) {//day
                                                        if (nums[g] <= 3) {
                                                            for (int h = g + 1; h <= n; ++h) {//day
                                                                if (nums[g] == 0 && nums[h] == 0) {
                                                                    continue;
                                                                }
                                                                string str = "2023";
                                                                int month = nums[e] * 10 + nums[f];
                                                                int day = nums[g] * 10 + nums[h];
                                                                str += to_string(nums[e]) + to_string(nums[f]);
                                                                str += to_string(nums[g]) + to_string(nums[h]);
                                                                if (day <= days[month]) {
                                                                    if (st.count(str)) {
                                                                        continue;
                                                                    }
                                                                    st.insert(str);
                                                                    puts(str.c_str());
                                                                    ++sum;
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            
        }
    }
    printf("%d\n",sum);
    return 0;
}

01串的熵

模拟题

#include <iostream>
#include <cmath>
using namespace std;
const int n = 23333333;
const double eps = 1e-4;
const double ans = 11625907.5798;
double f(int sum1, int sum0){
  double res = 0;
  double p1 = (double)sum1 / (double)n;
  double p0 = (double)sum0 / (double)n;
  res += p1 * sum1 * log2(p1);
  res += p0 * sum0 * log2(p0);
  return res;
}
int main()
{
  for (int i = 0; i <= n >> 1; ++ i)
  {
    if (fabs(-f(n - i, i) - ans) <= eps) 
    {
      cout << i;
      break;
    }
  }
  return 0;
}

冶炼金属

解法一:思维

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e4 + 10;
int n;
int maxx = 0, minn = 1e9;
int main()
{

  cin >> n;
  for (int i = 0; i < n; ++ i)
  {
    int a, b;
    cin >> a >> b; // a / v = b; a = b * v;
    maxx=max(maxx,a/(b+1) + 1) , minn=min(minn,a/b);
  }
  cout << maxx << " " << minn;
  return 0;
}

解法二:二分

飞机降落

dfs暴力

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 11;
int t[N], d[N], l[N];
int st[N];
int n;
int ans;
bool dfs(int cnt, int time)
{
  if (cnt == n) 
  {
   return true;
  }
  for (int i = 0; i < n; ++ i)
  {
    if (st[i] == 0 && time <= t[i] + d[i])
    {
      st[i] = 1;
      cout << dfs(cnt + 1, max(time, t[i]) + l[i]);
      st[i] = 0;
    }
  }
  return false;
}
void solution()
{
  ans = 0;
  memset(st, 0, sizeof st);
  memset(t, 0, sizeof t);
  memset(l, 0, sizeof l);
  memset(d, 0, sizeof d);
  cin >> n;
  for (int i = 0; i < n; ++ i)
  {
    cin >> t[i] >> d[i] >> l[i];
  }
  if (dfs(0, 0)) cout << "YES" << endl;
  else cout << "NO" << endl;
  return;
}
int main()
{
  int T;
  cin >> T;
  while (T --) solution();
  return 0;
}

接龙数列

dp

#include<iostream>
#include<cstring>
using namespace std;
const int N = 1e5 + 10;
int dp[N];
int main()
{
    int n;
    cin >> n;
    int ans = 0;
    for (int i = 0; i < n; ++ i)
    {
        string s;
        cin >>s;
        int a = s[0] - '0', b = s.back() - '0';
        dp[b] = max(dp[a] + 1, dp[b]);
        ans = max(ans, dp[b]);
    }
    cout <<n - ans;
    return 0;
}

岛屿个数

解法一:染色 + 合并 + 统计

和常规的染色题目相比, 本题多了一个合并的步骤, 染色的时候通过八联通将各个岛屿分开, 并且将海水标记为2, 如果后续遍历地图的时候遇到了0, 说明这里是海水八联通进不来的地方, 直接用岛屿的标志1去合并这一整个镂空的岛屿 , 类似这样把这个岛里面铺满;
在这里插入图片描述
如果像下面这样, 外面的岛没有把里面的岛完全包围的情况, 那么也符合我们的预期, 他们是两个岛屿, 在dfs4(四联通)的时候会统计成两个岛屿
在这里插入图片描述

#include<iostream>
#include<cstring>
using namespace std;
const int N = 52;
char g[N][N];
int T, n, m;
int ans;
int dx8[] = {1, 0, -1, 0, 1, 1, -1, -1}, dy8[] = {0, 1, 0, -1, 1, -1, 1, -1};

int dx4[] = {0, 1, 0, -1}, dy4[] = {1, 0, -1, 0};

void dfs4(int x, int y)
{
    g[x][y] = '2';
    int xx, yy;
    for (int i = 0; i <4; ++ i)
    {
        xx = x + dx4[i], yy = y + dy4[i];
        if (g[xx][yy] == '1' && xx >= 0 && xx <= n && yy >= 0 && yy <= m)
        {
            dfs4(xx, yy);
        }
    }
}
void dfs8(int x, int y)
{
    g[x][y] = '2';
    for (int i = 0; i < 8; ++ i)
    {
        int xx = x + dx8[i], yy = y + dy8[i];
        if (g[xx][yy] == '0' && xx >= 0 && xx <= n + 1 && yy >= 0 && yy <= m + 1 )
        {
            dfs8(xx, yy);
        }
    }
}
int main()
{   
    cin >> T;
    while (T --)
    {
        ans = 0;
        cin >> n >> m;
        //初始化
        for (int i = 0; i < n + 2; ++ i)
            for (int j = 0; j < m + 2; ++ j)
                g[i][j] = '0';
        // io
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= m; ++ j) 
                cin >> g[i][j];
                
        //染海水
        dfs8(0, 0);
        //合并, 海水进不来的地方说明被岛屿全包围了, 那么直接变成1合并成一个岛屿
        for (int i = 1; i <= n; ++ i)
        {
            for (int j = 1; j <= m; ++ j)
                if (g[i][j] == '0') g[i][j] = '1';
        }
        
        //统计岛屿数量
        for (int i = 1; i <= n; ++ i)
        {
            for (int j = 1; j <= m; ++ j)
                if (g[i][j] == '1') 
                {
                    ans ++;
                    dfs4(i, j);
                }
        }
        cout << ans << endl;
    }
    return 0;
}

解法二: 给岛屿染色, 统计有多少种不同的颜色

学习这个博主的
坑: 多组测试数据记得memset g 和st, 我就是没有memset st 一直wa;
思路:

  • 给每个岛屿染上不同的颜色(用四联通 dfs4)
  • 通过海水进行八连通dfs8遍历岛屿数目, 记得dfs8中将遍历过的海水从0 变为 -1 , 否则dfs会爆内存
#include<iostream>
#include<cstring>
using namespace std;
const int N = 52;
int g[N][N];
int T, n, m;
int ans, k = 2;
int dx8[] = {1, 0, -1, 0, 1, 1, -1, -1}, dy8[] = {0, 1, 0, -1, 1, -1, 1, -1};
int dx4[] = {0, 1, 0, -1}, dy4[] = {1, 0, -1, 0};
int st[N];
void dfs4(int x, int y)
{
    g[x][y] = k;
    int xx, yy;
    for (int i = 0; i < 4; ++ i)
    {
        xx = x + dx4[i], yy = y + dy4[i];
        if (g[xx][yy] == 1 && xx >= 1 && xx <= n && yy >= 1 && yy <= m)
        {
            dfs4(xx, yy);
        }
    }
}
void dfs8(int x, int y)
{
    g[x][y] = -1;
    for (int i = 0; i < 8; ++ i)
    {
        int xx = x + dx8[i], yy = y + dy8[i];
        if (xx >= 0 && xx <= n + 1 && yy >= 0 && yy <= m + 1)
        {
            if (g[xx][yy] >= 2 && !st[g[xx][yy]])
            {
                st[g[xx][yy]] = 1;
                ans ++;
            }
            if (g[xx][yy] == 0) dfs8(xx, yy);
        }
    }
}
int main()
{   
    cin >> T;
    while (T --)
    {
        ans = 0;
        k = 2;
        cin >> n >> m;
        //初始化
        memset(g, 0, sizeof g);
        memset(st, 0, sizeof st);
        // io
        for (int i = 1; i <= n; ++i)
        {
            string x;
            cin >> x;
            for (int j = 1; j <= m; ++ j) 
            {
                
                g[i][j] = x[j - 1] - '0';
            }
        }
            
                
        for (int i = 1; i <= n; ++ i)
        {
            for (int j = 1; j <= m; ++ j)
            {
                if (g[i][j] == 1) 
                {
                    dfs4(i, j);
                    k ++;
                }
            }
        }
        dfs8(0, 0);
        cout << ans << endl;
    }
    return 0;
}

子串简写

后缀和
记得ans开long long

#include<iostream>
#include<string>
#include <queue>
using namespace std;
const int N = 5e5 + 10;
int k;
string s;
char c1, c2;
int cnt[N];
int main()
{
    long long ans = 0;
    cin >> k >> s >> c1 >> c2;
    for (int i = s.size() - 1; i >= 0; --i)
    {
        cnt[i] = cnt[i + 1];
        if (s[i] == c2) cnt[i] ++;
    }
    for (int i = 0; i + k - 1 < s.size(); ++ i)
    {
        if (s[i] == c1) ans += cnt[i + k - 1];
    }
    cout << ans;
    return 0;
}

整数删除

数组模拟双向链表, 优先队列; 这题考的数据结构
注意模拟双向链表的时候 r[0] = 1; l[n + 1] = n;


#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
typedef long long LL;
typedef pair<LL, LL> PLL;
int n, k;
LL a[N], l[N], r[N];

void del(LL i)
{
    //把i的值加到i的左边和右边
    a[l[i]] += a[i], a[r[i]] += a[i];
    //i的左边指向i的右边, i的右边指向i的左边, 
    r[l[i]] = r[i];
    l[r[i]] = l[i];
}

int main()
{
    cin >> n >> k;
    r[0] = 1; l[n + 1] = n;
    priority_queue<PLL, vector<PLL>, greater<PLL>> q;
    for (int i = 1; i <= n; ++ i) 
    {
      //正好缺一个r[0] = 1; l[n + 1] = n;
        l[i] = i - 1; r[i] = i + 1;
        cin >> a[i];
        q.push({a[i], i});
    }
    
    while (k -- )
    {
        PLL u = q.top();
        q.pop();
        auto [v, vi] = u;
        if (v != a[vi]) 
        {
            q.push({a[vi], vi});
            k ++ ;
        }
        else del(vi);
    }
    
    for (int i = r[0]; i != n + 1; i = r[i])
    {
        cout << a[i] << " ";
    }
    return 0;
}

砍树(LCA + 树上差分)

树上差分就是要用到LCA的板子
本题题解
树上边差分博客
树上点差分博客
注意点差分和边差分的区别;
具有抽象思维: 联通块类的题目每个点连接父节点的那条边的贡献度是1
数据范围又开小了,导致一直是前6个点能过 后面十几个点过不了(看到这里前几个能过后面过不了就应该想到是数据范围开小了的)

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int N = 5e5 + 10;
int h[N], e[N], ne[N], idx;
int s[N], ans = -1;
int d[N], f[N][21];
int n, m;
void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

void dfs(int u, int fa)
{   
    if(d[u]) return;
    //预处理d[]
    d[u] = d[fa] + 1;
    f[u][0] = fa;
    //预处理f[]
    for (int k = 1; k <= 20; ++k)
    {
        f[u][k] = f[f[u][k - 1]][k - 1];
    }
    for (int i = h[u]; ~i; i = ne[i])
    {
        int v = e[i];
        if(v == fa) continue;
        dfs(v, u);
    }
}
int lca(int a, int b)
{
    if (d[a] < d[b]) swap(a, b);
    for (int k = 20; k >= 0; -- k)
    {
        if (d[f[a][k]] >= d[b]) a = f[a][k];
    }
    if (a == b) return a;
    for (int k = 20; k >= 0; -- k)
    {
        if (f[a][k] == f[b][k]) continue;
        a = f[a][k], b = f[b][k];
    }
    
    return f[a][0];
}

void update(int u, int fa, int id, int &ans)
{
    for (int i = h[u]; ~i; i = ne[i])
    {
        int v = e[i];
        if (v == fa) continue;
        update(v, u, i, ans);
        s[u] += s[v];
    }
    if (s[u] == m)
    {
        ans = max(ans, id / 2 + 1);
    }
}



int main()
{
    cin >> n >> m;
    memset(h, -1, sizeof h);
    for (int i = 0; i < n - 1; ++i)
    {
        int a, b;
        cin >> a >> b;
        add(a, b), add(b, a);
    }
    //在lca前!!预处理d[]和f[];
    dfs(1, 0);
    for (int i = 0; i < m; ++ i)
    {
        int x, y;
        cin >> x >> y;
        s[x] ++, s[y] ++, s[lca(x, y)] -= 2;
    }
    //根节点为自定义的哨兵0, f[1] = 0;
    //一个图从哪里开始遍历都行, 哪里拎起来都是一棵树
    update(1, 0, 0, ans);
    cout << ans;
    return 0;
}
  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
蓝桥杯是一个国内著名的计算机比赛,为了帮助参赛者更好地准备和了解比赛的题型,组委会会公布历真题并提供相应的题解。 首先,我们需要了解蓝桥杯是一个综合性的计算机比赛,测试的对象包括计算机基础知识、编程能力以及解决实际问题的能力。 在历真题中,参赛者将面临不同类型的题目,包括算法设计与优化问题、数据结构与算法问题、编程题等。其中针对Python B组的题目主要考察的是对Python语言的掌握和应用能力。 题目解答一般会包含以下几个方面的内容: 1. 题目分析与理解:读取题目,理解题目的要求和限制条件。通过仔细分析题目,确定题目的输入与输出,以及问题的核心。 2. 设计解决方案:根据题目要求和限制条件,设计一个合适的解决方案。可以使用合适的算法和数据结构来解决问题,并做出相应的性能优化。 3. 编写代码实现:根据设计的方案编写相应的代码实现。需要注意的是,Python语言有其独特的语法和特性,掌握好这些特性可以更好地完成编程任务。 4. 调试与测试:编写完代码后,需要进行调试和测试。通过运行样例输入和输出,检查代码是否符合题目要求,并且没有逻辑上的错误。 5. 总结与优化:在完成题目解答后,可以进行总结和优化。包括分析算法复杂度、代码风格和可读性等方面,以便在比赛中更好地表现。 在准备蓝桥杯时,可以通过阅读历真题题解来了解比赛的难度和类型,针对性地进行练习和提高。同时也可以参加相关的培训班和讨论活动,与其他参赛者交流经验和技巧。 总而言之,历蓝桥杯真题的解答对于提高自己的编程能力和应对比赛非常有帮助。通过认真分析和实践,可以更好地理解并掌握Python编程,并在比赛中取得更好的成绩。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值