蓝桥杯练习系统 历届真题


题目链接

PREV-1 核桃的数量

输出三者的最小公倍数即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e3 + 10;
const int INF = 0x3f3f3f3f;
int main(){
    ll a, b, c;
    scanf("%lld %lld %lld", &a, &b, &c);
    ll tem = a * b / __gcd(a, b);
    ll ans = tem * c / __gcd(tem, c);
    printf("%lld\n", ans);
    return 0;
}

PREV-2 打印十字图

数据量小,暴力遍历,在周围加上一圈’.‘或者一圈’$’

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e4 + 10;
const int INF = 0x3f3f3f3f;
char s[maxn][maxn];
bool near(int x, int y, char ch){
    if(s[x - 1][y - 1] == ch || s[x - 1][y] == ch || s[x - 1][y + 1] == ch || s[x][y - 1] == ch || s[x][y + 1] == ch || s[x + 1][y - 1] == ch || s[x + 1][y] == ch || s[x + 1][y + 1] == ch){
        return true;
    }
    return false;
}
int main(){
    int n; scanf("%d", &n);
    for(int i = 1; i <= 200; i++){
        for(int j = 1; j <= 200; j++){
            s[i][j] = '#';
        }
    }
    int pos = 100;
    s[pos][pos] = s[pos][pos - 1] = s[pos][pos - 2] = s[pos][pos + 1] = s[pos][pos + 2] = s[pos - 1][pos] = s[pos - 2][pos] = s[pos + 1][pos] = s[pos + 2][pos] = '$';
    for(int t = 1; t <= 2 * n; t++){///&1 涂'.' 偶数涂'$'
        if(t & 1){
            for(int i = 1; i <= 200; i++){
                for(int j = 1; j <= 200; j++){
                    if(s[i][j] != '#'){
                        continue;
                    }
                    if(near(i, j, '$')){
                        s[i][j] = '.';
                    }
                }
            }
        }else{
            for(int i = 1; i <= 200; i++){
                for(int j = 1; j <= 200; j++){
                    if(s[i][j] != '#'){
                        continue;
                    }
                    if(near(i, j, '.')){
                        s[i][j] = '$';
                    }
                }
            }
        }
    }
    for(int i = pos - 2 - n * 2; i <= pos + 2 + n * 2; i++){
        for(int j = pos - 2 - n * 2; j <= pos + 2 + n * 2; j++){
            if(s[i][j] == '#'){
                printf(".");
            }else{
                printf("%c", s[i][j]);
            }
        }printf("\n");
    }
    return 0;
}

PREV-3 带分数

直接枚举所有的排列方式,1~9的全排列有2的9次方,1000个左右。
对于每个排列,枚举a b c三个数字的所有可能的位数,做一个分割验证。枚举a b c要1000不到,总的时间1e6

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e4 + 10;
const int INF = 0x3f3f3f3f;
int a[100];
int n;
bool check(int x, int y, int z){
    int i;
    int aa = 0, b = 0, c = 0;
    for(i = 1; i <= x; i++){
        aa *= 10;
        aa += a[i];
    }
    for(; i <= y; i++){
        b *= 10;
        b += a[i];
    }
    for(; i <= z; i++){
        c *= 10;
        c += a[i];
    }
    if(b % c != 0)
        return false;
    if(n == aa + b / c )
        return true;
    return false;
}
int main(){
    scanf("%d", &n);
    for(int i = 1; i <= 9; i++){///排列
        a[i] = i;
    }
    int ans = 0;
    do{
        ///对于每一个排列,都进行验证
        for(int i = 1; i <= 7; i++){
            for(int j = i + 1; j <= 8; j++){
                int k = 9;
                if(k - j >= 1){
                    if(check(i, j, k)){
                        ans++;
                    }
                }
            }
        }
    }while(next_permutation(a + 1, a + 1 + 9));
    printf("%d\n", ans);
    return 0;
}

PREV-4 剪格子

dfs搜索即可,以左上角作为起始搜索点,记录搜索到当前位置的连通块的大小,以及这些数字的和。
需要注意的是输入是先输入m再输入n(先列后行)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e2 + 10;
const int INF = 0x3f3f3f3f;
int G[maxn][maxn];
bool vis[maxn][maxn];
int n, m, tot;
int dx[] = {-1, 0, 0, 1};
int dy[] = {0, 1, -1, 0};
queue <pii> que;
int dfs(int x, int y, int sum, int sz){
    //printf("%d %d\n", x, y);
    vis[x][y] = true;
    if(2 * sum == tot)
        return sz;
    if(2 * sum > tot)
        return INF;
    int mini = INF;
    for(int i = 0; i < 4; i++){
        int nxt_x = x + dx[i], nxt_y = y + dy[i];
        if(nxt_x >= 1 && nxt_y >= 1 && nxt_x <= n && nxt_y <= m && !vis[nxt_x][nxt_y]){
            mini = min(mini, dfs(nxt_x, nxt_y, sum + G[nxt_x][nxt_y], sz + 1));
            vis[nxt_x][nxt_y] = false;
        }
    }
    return mini;
}
int main(){
    scanf("%d %d", &m, &n);
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            scanf("%d", &G[i][j]);
            tot += G[i][j];
        }
    }
    if(tot & 1){
        printf("0\n");
    }else{
        int ans = dfs(1, 1, G[1][1], 1);
        printf("%d\n", ans);
    }
    return 0;
}

PREV-5 票据

读取数据,排序看一下

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e4 + 10;
const int INF = 0x3f3f3f3f;
int a[maxn];
char s[maxn];
int main(){
    int n; scanf("%d", &n); getchar();
    int cnt = 0;
    for(int i = 1; i <= n; i++){
        cin.getline(s, maxn);
        int x = 0;
        for(int j = 0; j < strlen(s); j++){
            if(s[j] >= '0' && s[j] <= '9'){
                x *= 10;
                x += s[j] - '0';
            }else{
                if(x){
                    a[++cnt] = x;
                }
                x = 0;
            }
            if(j == strlen(s) - 1){
                if(x)
                    a[++cnt] = x;
            }
            //printf("i:%d\n", i);
        }
    }
    sort(a + 1, a + 1 + cnt);
    for(int i = 2; i <= cnt; i++){
        if(a[i] - a[i - 1] == 2){
            printf("%d ", a[i] - 1);
        }
    }
    for(int i = 2; i <= cnt; i++){
        if(a[i] == a[i - 1]){
            printf(" %d\n", a[i]);
        }
    }
    return 0;
}

PREV-6 翻硬币

翻硬币游戏,从左往右贪心做即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e3 + 10;
const int INF = 0x3f3f3f3f;
char s[maxn], ss[maxn];
void rev(char* p){
    if(*p == '*')
        *p = 'o';
    else if(*p == 'o')
        *p = '*';
}
int main(){
    scanf("%s", s);
    scanf("%s", ss);
    int len = strlen(s);
    int ans = 0;
    for(int i = 0; i < len; i++){
        if(s[i] != ss[i]){
            ans++;
            rev(s + i);
            if(i + 1 < len)
                rev(s + i + 1);
        }
    }
    printf("%d\n", ans);
    return 0;
}

PREV-7 连号区间数

n是5e4级别的,1s时限居然能用O(n^2)的方法做,这个评测机是战斗机吧。
其实是数据水了,数组开1e4的空间也能过。

直接枚举区间左右端点,判断当前区间是否是某个连续的,根据最大值减去最小值是否等于区间长度即可。(因为没有重复元素,可以这么算)

打正赛的时候要记得,不会做就暴力莽一发。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e6 + 10;
const int INF = 0x3f3f3f3f;
int n;
int a[maxn];
void solve(){
    ll ans = 0;
    for(int i = 1; i <= n; i++){
        int maxi = -1;
        int mini= INF;
        for(int j = i; j <= n; j++){
            maxi = max(maxi, a[j]);
            mini = min(mini, a[j]);
            if(maxi - mini == j - i)
                ans++;
        }
    }
    printf("%lld\n", ans);
}
int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        scanf("%d", &a[i]);
    }
    solve();
    return 0;
}

PREV-8 买不到的数目

暴力能过,直接枚举可达状态,取不可达的最大的,枚举到1e6即可。

直接求解是ab-a-b,可用找规律的方法找到。
也可证明ab-a-b是正解,具体见其他博客。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e8 + 10;
const int INF = 0x3f3f3f3f;
bool dp[maxn];
void solve(int x, int y){
    dp[x] = dp[y] = true;
    int pos;
    for(int i = 0; i < 1e6; i++){
        if(i - y > 0){
            if(dp[i - y] || dp[i - x]){
                dp[i] = true;
            }else{
                pos = i;
            }
        }
        else if(i - x > 0){
            if(dp[i - x]){
                dp[i] = true;
            }else{
                pos = i;
            }
        }else{
            pos = i;
        }
    }
    printf("%d\n", pos);
}
int main(){
    int n, m;
    scanf("%d %d", &n, &m);
    if(n > m)
        swap(n, m);
    solve(n, m);
    return 0;
}

PREV-9 大臣的旅费

两次dfs跑出树的直径,然后因为花费是等差数列,直接根据式子算出答案即可。
要注意vis[1]在第一次dfs后要置为false。
或者dfs添加pre避免重复走。

发现数据很水

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e7 + 10;
const int INF = 0x3f3f3f3f;
struct Node{
    ll v, c;
};
bool vis[maxn];
ll n, tot_dis = -1, tot_pos = -1;
vector <Node> G[maxn];
void dfs(ll u, ll dis){
    vis[u] = true;
    if(dis > tot_dis){
        tot_dis = dis;
        tot_pos = u;
    }
    for(ll i = 0; i < G[u].size(); i++){
        ll v = G[u][i].v, c = G[u][i].c;
        if(!vis[v]){
            dfs(v, dis + c);
            vis[v] = false;
        }
    }
    return ;
}
int main(){
    scanf("%lld", &n);
    for(ll i = 1, x, y, z; i < n; i++){
        scanf("%lld %lld %lld", &x, &y, &z);
        G[x].push_back(Node{y, z});
        G[y].push_back(Node{x, z});
    }
    ///求树的直径
    dfs(1ll, 0ll);
    vis[1] = false;///****
    tot_dis = -1ll;
    dfs(tot_pos, 0ll);
    printf("%lld\n", (21ll + tot_dis) * tot_dis / 2ll);
    return 0;
}
/*
3
1 2 76
3 2 74
*/

PREV-10 幸运数

直接O(N^2)暴力筛掉即可AC

PREV-14 高僧斗法

nim博弈,看奇偶性,算异或即可。
从小到大枚举第一步操作,能让对方必败态则为该操作。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e3 + 10;
int a[maxn];

int main(){
    int n = 0;
    char c;
    while(1){
        scanf("%d%c", &a[++n], &c);
        if(c == '\n')
            break;
    }
    int ans = 0;
    for(int i = 2; i <= n; i += 2){
       ans ^= a[i] - a[i - 1] - 1;
    }

    bool flag = false;
    int k;
    if(ans == 0)///必败态
        printf("-1\n");
    else{
        for(int i = 1; i < n; i++){
            for(int j = a[i]; j < a[i + 1]; j++){
                k = a[i];
                a[i] = j;
                int ans = 0;
                for(int x = 2; x <= n; x += 2){
                    ans ^= a[x] - a[x - 1] - 1;
                }
                if(ans == 0){///让对方成为必败态
                    flag = true;
                    printf("%d %d\n", k, j);
                    break;
                }
                a[i] = k;
            }
            if(flag){
                break;
            }
        }
    }
    return 0;
}

PREV-21 回文数字

#include <bits/stdc++.h>
using namespace std;
int dit[10];
int n;
bool check(int x){
    int cnt = 0, sum  = 0;
    while(x){
        dit[++cnt] = x % 10;
        sum += x % 10;
        x /= 10;
    }
    int l = 1, r = cnt;
    bool flag = true;
    while(l < r){
        if(dit[l] != dit[r]){
            flag = false;
            break;
        }
        l++;
        r--;
    }
    if(sum != n)
        flag = false;
    return flag;
}
int main(){
    scanf("%d", &n);
    bool flag = false;
    for(int i = 10000; i < 1000000; i++){
        if(check(i)){
            flag = true;
            printf("%d\n", i);
        }
    }
    if(!flag){
        printf("-1\n");
    }
    return 0;
}

PREV-46 填字母游戏

这题很卡时间,很容易TLE。
要记忆化搜索,记忆化搜索博弈状态。
判断当前状态是否存在用mp.count(s) 别用 mp[s],不然也会T
在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
string s;
map <string, int> mp;
int solve(){
    if(mp.count(s)){
        return mp[s];
    }
    if(s.find("LOL") != -1){///找到LOL
        return -1;
    }
    if(s.find("*") == -1){///没有空格,平局
        return 0;
    }
    bool p = false;///平局标记
    for(int i = 0; i < s.size(); i++){
        if(s[i] == '*'){
            s[i] = 'L';
            int ret = solve();
            s[i] = '*';
            if(ret == -1){
                return mp[s] = 1;
            }else if(ret == 0){
                p = true;
            }

            s[i] = 'O';
            ret = solve();
            s[i] = '*';
            if(ret == -1){
                return mp[s] = 1;
            }else if(ret == 0){
                p = true;
            }
        }
    }
    if(p)
        return mp[s] = 0;
    return -1;
}
int main(){
    int t; scanf("%d", &t);
    while(t--){
        cin >> s;
        printf("%d\n", solve());
    }
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值