第八届蓝桥杯省赛C++B组题解

本文探讨了日期问题的排序与去重技巧,优化了购物清单计算方法,涉及等差素数列、承压计算、方格分割等算法实现。还介绍了如何使用编程处理日期、数位提取及最大公共子串问题。

总结

日期问题,注意判重和排序,搜索优化搜索方式,逆向思维。

购物单

方法1: 在excel中计算,复制粘贴后对数据进行以空格为标志分列,删除汉字,用公式计算。
方法2: 利用ctrl+F快捷键,将购物单复制到代码中,把**** 替换成+号,去掉汉字`折`,改为两位数 
         即9折改成90,在数字间加上 *,计算结果除以100即可,此方法不至于输入错误。
5200

等差素数列

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 500010;

int primes[N], cnt;
bool st[N];

void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i]) primes[cnt ++ ] = i;
        for (int j = 0; primes[j] <= n / i; j ++ )
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) break;
        }
    }
}

int main()
{
    get_primes(N - 1);
    
    int k = 0;
    for (int i = 0; i < cnt; i ++ )
    {
        for (int j = 1; j <= 10000; j ++ )
        {
            for (k = 1; k < 10; k ++ )
            {
                if (st[primes[i] + k * j]) break;
            }
            if (k == 10)
            {
                cout << j << endl;
                return 0;
            }
        }
    }
    return 0;
}

承压计算

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 50;

int n = 30;
double g[N][N];
typedef long long LL;

int main()
{
    for (int i = 1; i < n; i ++ )
        for (int j = 1; j <= i; j ++ )
            cin >> g[i][j];
    
    for (int i = 1; i < n; i ++ )
        for (int j = 1; j <= i; j ++ )
        {
            g[i + 1][j] += g[i][j] / 2;
            g[i + 1][j + 1] += g[i][j] / 2;
        }
    
    double minn = 1e18, maxn = 0;
    for (int i = 1; i <= n; i ++ )
    {
        minn = min(minn, g[30][i]);
        maxn = max(maxn, g[30][i]);
    }
    
    printf("%.0lf", 2086458231 / minn * maxn);
    return 0;
}

方格分割

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 10;
bool st[N][N];
int ans = 0;

int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};

void dfs(int x, int y)
{
    if (x == 0 || y == 0 || x == 6 || y == 6)
    {
        ans ++ ;
        return;
    }
    
    for (int i = 0; i < 4; i ++ )
    {
        int nx = x + dx[i], ny = y + dy[i];
        if (st[nx][ny]) continue;
        st[nx][ny] = true;
        st[6 - nx][6 - ny] = true;
        dfs(nx, ny);
        st[nx][ny] = false;
        st[6 - nx][6 - ny] = false;
    }
}

int main()
{
    st[3][3] = true;
    dfs(3,3);
    cout << ans / 4 << endl;
    return 0;
}

取数位

#include <stdio.h>
// 求x用10进制表示时的数位长度 
int len(int x){
    if(x<10) return 1;
    return len(x/10)+1;
}
    
// 取x的第k位数字
int f(int x, int k){
    if(len(x)-k==0) return x%10;
    return f(x/10,k);
}
    
int main()
{
    int x = 23574;
    printf("%d\n", f(x,3));
    printf("%d\n", f(893275,2));
}

最大公共子串

#include <stdio.h>
#include <string.h>

#define N 256
int f(const char* s1, const char* s2)
{
    int a[N][N];
    int len1 = strlen(s1);
    int len2 = strlen(s2);
    int i,j;
    
    memset(a,0,sizeof(int)*N*N);
    int max = 0;
    for(i=1; i<=len1; i++){
        for(j=1; j<=len2; j++){
            if(s1[i-1]==s2[j-1]) {
                a[i][j] = a[i - 1][j - 1] + 1;
                if(a[i][j] > max) max = a[i][j];
            }
        }
    }
    
    return max;
}

int main()
{
    printf("%d\n", f("abcdkkk", "baabcdadabc"));
    printf("%d\n", f("aaakkkabababa", "baabababcdadabc"));
    printf("%d\n", f("abccbaacbcca", "ccccbbbbbaaaa"));    
    printf("%d\n", f("abcd", "xyz"));
    printf("%d\n", f("ab", "ab"));
    return 0;
}

日期问题

这道题还需要排序、判重如果单独判断可能有点小麻烦,如果暴力遍历的就没有这些问题hh

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

int y, m, d;
int months[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int cnt;
struct Date
{
    int y, m, d;
    int date;
    
    bool operator< (const Date& t) const
    {
        if (y != t.y) return y < t.y;
        else if (m != t.m) return m < t.m;
        return d < t.d;
    }
}date[3];

bool is_yeap(int y)
{
    if (m != 2) return false;
    return y % 4 == 0 && y % 100 != 0 || y % 400 == 0;
}

bool check(int a, int b, int c)
{
    if (a < 60) y = a + 2000;
    else y = a + 1900;
    
    m = b, d = c;
    if (b < 1 || b > 12) return false;
    if (c < 1 || c > months[b] + is_yeap(y)) return false;
    return true;
}

int main()
{
    int a, b, c;
    scanf("%d/%d/%d", &a, &b, &c);
    
    
    if (check(a, b, c)) date[cnt ++ ] = {y, m, d, y*10000+m*100+d};
    if (check(c, a, b)) date[cnt ++ ] = {y, m, d, y*10000+m*100+d};
    if (check(c, b, a)) date[cnt ++ ] = {y, m, d, y*10000+m*100+d};

    sort(date, date + cnt);
    
    for (int i = 0; i < cnt; i ++ )
        if (i && date[i].date == date[i - 1].date) continue;
        else printf("%d-%02d-%02d\n", date[i].y, date[i].m, date[i].d);
    return 0;
}

包子凑数

先判断最大公约数如果>1无解,用DP存储不能凑到的数量,转化为完全背包问题

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 110, M = 10005;

int n;
int w[N];
bool f[M];

int gcd(int a, int b)  // 欧几里得算法
{
    return b ? gcd(b, a % b) : a;
}

int main()
{
    cin >> n;
    int d = 0;
    for (int i = 1; i <= n; i ++ ) 
    {
        cin >> w[i];
        d = gcd(d, w[i]);
    }
    
    if (d > 1) puts("INF");
    else
    {
        f[0] = true;
        for (int i = 1; i <= n; i ++ )
        {
            for (int j = w[i]; j <= M; j ++ )
                f[j] |= f[j - w[i]];
        }
        
        int res = 0;
        for (int i = 1; i < M; i ++ )
            res += f[i]==0;
        printf("%d\n", res);
    }
    
    return 0;
}

分巧克力

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 100010;
int n, k;
int h[N], w[N];

bool check(int mid)
{
    int cnt = 0;
    for (int i = 1; i <= n; i ++ )
    {
        cnt += (h[i] / mid) * (w[i] / mid);
        if (cnt >= k) return true;
    }
    return false;
}

int main()
{
    cin >> n >> k;
    for (int i = 1; i <= n; i ++ ) scanf("%d%d", &h[i], &w[i]);
    
    int l = 1, r = N;
    while (l < r)
    {
        int mid = l + r + 1>> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    cout << r << endl;
    return 0;
}

k倍区间

枚举右端点,哈希记录左端点多少个右端点同%k

#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>

using namespace std;
typedef long long LL;

const int N = 100010;
int n, k;
LL s[N];
map<LL, int> mp;

int main()
{
    scanf("%d%d", &n, &k);
    
    mp[0] ++ ;
    LL res = 0;
    for (int i = 1; i <= n; i ++ )
    {
        scanf("%lld", &s[i]);
        s[i] = (s[i] + s[i - 1]) % k;
        
        res += mp[s[i]];
        mp[s[i]] ++ ;
    }
    printf("%lld\n", res);
    return 0;
}
### 第十三届蓝桥杯 C++ B 题目及题解 #### 试题 A: 空间 对于空间问题,通常涉及计算几何或简单的数学运算。具体到此题,可能涉及到三维坐标系中的距离计算或其他基本的空间关系处理。 ```cpp #include <iostream> using namespace std; int main() { double x1, y1, z1; double x2, y2, z2; cin >> x1 >> y1 >> z1; cin >> x2 >> y2 >> z2; double distance = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1)); cout << fixed << setprecision(2) << distance << endl; return 0; } ``` [^1] #### 试题 B: 卡片 卡片问题一般考察的是合数学的知识点或者是字符串操作技巧。这类题目往往需要理解排列合原理以及如何高效地遍历所有可能性来找到最优解法。 ```cpp #include <bits/stdc++.h> using namespace std; string cards[] = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K"}; vector<string> deck(cards, end(cards)); void shuffleDeck(vector<string>& d){ random_shuffle(d.begin(),d.end()); } int main(){ srand(time(NULL)); // 初始化随机数种子 do{ shuffleDeck(deck); for(auto card : deck) cout<<card<<" "; cout<<"\n"; }while(getchar()!='q'); return 0; } ``` [^2] #### 试题 C: 直线 直线问题是关于解析几何的基础应用之一,比如求两条直线交点、判断两直线平行与否等问题。解决此类问题的关键在于掌握好斜率的概念及其相关性质的应用方法。 ```cpp struct Line { double a,b,c; // ax+by+c=0 形式的系数表示一条直线 }; bool isParallel(Line l1,Line l2){ return abs(l1.a*l2.b-l1.b*l2.a)<EPSILON; } pair<double,double> intersectionPoint(Line l1,Line l2){ double det=l1.a*l2.b-l1.b*l2.a; if(abs(det)>EPSILON){ // 不平行则有唯一交点 double px=(l2.c*l1.b-l1.c*l2.b)/det; double py=(l1.c*l2.a-l2.c*l1.a)/det; return make_pair(px,-py); // 注意这里返回的纵坐标取负号是因为我们定义方程时c项前面带了个减号 } throw runtime_error("Lines are parallel or coincident"); } ``` [^3] #### 试题 D: 货物摆放 货物摆放示例展示了动态规划算法的实际应用场景。通过构建状态转移表并逐步填充表格中的值直到最终得到全局最优解的过程体现了该类问题的核心思想——分治策略下的最优化选择。 ```cpp const int MAXN=1e5+5; long long dp[MAXN],w[MAXN]; for(int i=1;i<=n;++i){ for(int j=m;j>=v[i];--j){ dp[j]=max(dp[j],dp[j-v[i]]+w[i]); } } cout<<dp[m]<<endl; ``` #### 试题 E: 路径 路径寻找属于图论范畴内的经典难题,无论是广度优先搜索还是深度优先搜索都能很好地解决问题;而当引入权重概念之后,则可以考虑采用Dijkstra算法或是Floyd-Warshall等更高级别的解决方案来进行分析解答。 ```cpp // 使用队列实现BFS查找最短路径长度 queue<int> q; memset(dist,INF,sizeof dist); dist[s]=0;q.push(s); while(!q.empty()){ int u=q.front();q.pop(); for(int v:g[u]){ if(dist[v]==INF){ dist[v]=dist[u]+1; pre[v]=u; q.push(v); } } } if(dist[t]!=INF){ vector<int> path; for(int cur=t;cur!=-1;cur=pre[cur]) path.push_back(cur); reverse(path.begin(),path.end()); printf("%d\n%d\n",dist[t],path.size()-1); for(size_t i=0;i<path.size();++i) printf(i==path.size()-1?"%d\n":"%d ",path[i]); }else puts("-1"); // 如果无法到达终点就输出-1 ``` #### 试题 F: 时间显示 时间转换是一个非常基础但也容易出错的小知识点,尤其是在不同单位之间的相互转化上要特别小心精度丢失的情况发生。下面给出了一种较为通用的时间格式化函数模板供参考学习之用。 ```cpp stringstream ss; ss<<setfill('0')<<setw(2)<<hour<<':'<<setw(2)<<minute<<':'<<setw(2)<<second; return ss.str(); ``` #### 试题 G: 砝码称重 砝码称重问题可以通过贪心算法快速得出结论。每次选取当前可用的最大重量作为本次测量的标准,这样既能保证准确性又能减少不必要的复杂度提升效率。 ```cpp sort(weights.rbegin(),weights.rend()); // 对砝码按降序排序 double total_weight=accumulate(begin(weights),end(weights),(double)0.0); double current_sum=0.0; int count=0; for(double w:weights){ if(current_sum+w<=total_weight/2.0){ ++count; current_sum+=w; }else break; } printf("%.lf%%\n",(current_sum/(total_weight/2))*100); ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Shirandexiaowo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值