蓝桥杯Java 、C ++ 组历年真题题解(包括填空和代码填空)----持续更新

为了更好的备战蓝桥杯,笔者将按照每日更新两道题的速度,争取在赛前刷穿真题,同样希望本文也可以帮助到大家。

2017 年 省赛填空题 迷宫

题目链接

答案 = 31 
简单 dfs 

AC code

#include<bits/stdc++.h>
using namespace std;
char g[15][15];
bool vis[15][15];

bool dfs(int i,int j)
{
    if(i < 1|| i > 10 ||j < 1|| j > 10) return true;
    if(vis[i][j]) return false;
    vis[i][j] = true;
    if(g[i][j] == 'U') dfs(i - 1,j);
    else if(g[i][j] == 'D') dfs(i + 1,j);
    else if(g[i][j] == 'L') dfs(i,j - 1);
    else if(g[i][j] == 'R') dfs(i,j + 1);
}
int main()
{
    for(int i = 1;i <= 10;i ++)
      for(int j = 1;j <= 10;j ++)
        cin >> g[i][j];
    int cnt = 0;
    for(int i = 1;i <= 10;i ++)
      for(int j = 1;j <= 10;j ++)
      {
          memset(vis,false,sizeof vis);
          if(dfs(i,j)) cnt ++;
      }

    cout << cnt << endl;
    return 0;
}

2017 年 省赛填空题 跳蚱蜢

题目链接

答案 = 20 


类似八数码问题,想要将012345678 => 087654321
每次跳跃其实就是和 0 交换位置,每次的转移为 -2,-1,1,2 ,那么负数转移的时候可以注意到
可以通过 (i + 9) % 9 的方式滚动数组模拟环,解决了这些问题就可以开始愉快的bfs了

#include<bits/stdc++.h>
using namespace std;
struct node
{
    string str;
    int pos;
    int step;
};
queue<node> q;
set<string> vis;
void change(node now,int key)
{
    string s = now.str;
    swap(s[now.pos],s[(now.pos + key + 9) % 9]);
    if(vis.count(s) == 0)
    {
        vis.insert(s);
        q.push({s,(now.pos + key + 9) % 9,now.step + 1});
    }
}
int main()
{
    string start = "012345678";//初始状态
    q.push({start,0,0});
    while(q.size())
    {
        auto t = q.front();
        if(t.str == "087654321")//目标状态
        {
            cout << t.step << endl;
            break;
        }
        else
        {
            //将一层全都拓展完以后 再弹出
            change(t,-2);
            change(t,-1);
            change(t,1);
            change(t,2);
            q.pop();
        }
    }
    return 0;
}


2017 年 省赛填空题 方格分割

题目链接

答案 = 509 

我们可以注意到倘若我们要切成完全相同的图形那么切割的路线必定是会经过 (3,3) 点的,因为他是一个中心对称图形。
而且一个图形要被切断的条件是到达了这个6 * 6方块的边界,因为我们只需要从 (3,3) 开始 dfs ,碰到边界即存在一个合法方案,因为一个点抵达了边界,他的对称点必然也在边界之上,必定能将图形切断。然后最后要注意的是需要将答案除 4 ,因为中心对称的缘故会存在重复,比如说一直向上,向下,向左,向右切出来的图形是一样的。 

#include<bits/stdc++.h>
using namespace std;
int cnt = 0;
const int N = 10;
int g[N][N];
int dx[] = {1,-1,0,0};
int dy[] = {0,0,-1,1};
void dfs(int i,int j)
{
    if(i == 0 || i == 6 || j == 0 || j == 6)
    {
        cnt ++;
        return ;
    }
    for(int k = 0;k < 4;k ++)
    {
        int nx = i + dx[k];
        int ny = j + dy[k];
        if(g[nx][ny] == 0)
        {
            g[nx][ny] = 1;
            g[6 - nx][6 - ny] = 1;
            dfs(nx,ny);
            g[nx][ny] = 0;
            g[6 - nx][6 - ny] = 0;
        }
    }
}
int main()
{
    memset(g,0,sizeof g);
    g[3][3] = 1;
    dfs(3,3);
    cout << cnt / 4 << endl;
    return 0;
}

2017 年 省赛代码填空题 字母组串

题目链接

运用 dp 的思想,长度为 n 的包含 a 个 A,b 个 B,c 个 C 字母的答案一定是会从
1.长度为 n 的包含 a - 1 个 A,b 个 B,c 个 C 字母的答案
2.长度为 n 的包含 a 个 A,b - 1 个 B,c 个 C 字母的答案
3.长度为 n 的包含 a 个 A,b 个 B,c - 1 个 C 字母的答案

转移而来的,因此把 dp 的转移按递归写法写就成了
 

return f(a - 1,b,c,n - 1) + f(a,b - 1,c,n - 1) + f(a,b,c - 1,n - 1);


AC code

#include <stdio.h>

// a 个 A,b 个 B,c 个 C 字母,能组成多少个不同的长度为n的串。
int f(int a, int b, int c, int n)
{
    if(a < 0 || b < 0 || c < 0) return 0;
    if(n == 0) return 1; 
    
    return f(a - 1,b,c,n - 1) + f(a,b - 1,c,n - 1) + f(a,b,c - 1,n - 1);
}

int main()
{
    printf("%d\n", f(1,1,1,2));
    printf("%d\n", f(1,2,3,3));
    return 0;
}


2017 年 省赛代码填空题 字母组串

题目链接

思路

题目提示了用矩阵的思想解决,那么我们就将 s1 和 s2 作为行列

ex.

    b a a b c d a d a b c
a   0 1 1 0 0 0 1 0 1 0 0 
b   1 0 0 2 0 0 0 0 0 2 0 
c   0 0 0 0 3 0 0 0 0 0 3 
d   0 0 0 0 0 4 0 1 0 0 0 
k   0 0 0 0 0 0 0 0 0 0 0 
k   0 0 0 0 0 0 0 0 0 0 0 
k   0 0 0 0 0 0 0 0 0 0 0 

很容易就可以想到若  a[i][j] 匹配结果,那必然是 a[i - 1][j - 1] 匹配上的结果再+ 1
即串s1在第 i 位和 s2 的第 j 位匹配上了,那么匹配数必定是 s1i-1 位和 s2  的 j-1 的匹配情况 + 1

 AC code
 

#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]; 
                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;
}

2017 年 省赛 正则问题

题目链接

分析

有同学可能没读懂题意,我在这里举个例子应该就能看懂了

((xx|xxx)x|(x|xx))xx 

xx | xxx => 或上的结果要么是 xx 要么就是 xxx 在这里为了保证字符串最长 我们留下了 xxx
(xxx)x就是直接连接为 xxxx
然后(x|xx) 同理 我们留下了 xx
那么现在就是(xxxx | xx) => xxxx
(xxxx)xx => xxxxxx 
因此答案为 6

解法: 将正则表达式构建成一颗树,用 dfs 遍历求解即可

Java 

import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改
public class Main 
{
    
    static String s;
    static int k = 0;
    public static void main(String[] args)
    {
        Scanner in = new Scanner(System.in);
        s = in.next();
        in.close();
        System.out.println(dfs());
    }
    
    public static int dfs()//计算(.....)中的值
    {
        int res = 0;
        while(k < s.length())
        {
            if(s.charAt(k) == ')') return res;//遇到 ) 就说明 () 内的已经计算完毕 直接返回即可
            else if(s.charAt(k) == '(') 
            {
                k ++;//跳过 (
                res += dfs();
                k ++;// 跳过 )
            }
            else if(s.charAt(k) == '|')
            {
                k ++;
                res = Math.max(res,dfs());// 左右取大
            }
            else 
            {
                k ++;//跳过 x
                res ++;//字符串长度增加
            }
        }
        return res;
    }
}

C ++

#include<bits/stdc++.h>
using namespace std;
string str;
int k;
int dfs()
{
    int res = 0;
    while(k < str.size())
    {
        if(str[k] == ')') break;
        if(str[k] == '(')
        {
            k ++;
            res += dfs();
            k ++;
        }
        else if(str[k] == '|')
        {
            k ++;
            res = max(res,dfs());
        }
        else 
        {
            k ++;
            res += 1;
        }
    }
    return res;
}
int main()
{
    cin >> str;
    cout << dfs() << endl;
    return 0;
}

2017 年 省赛 包子凑数

题目链接

分析


由裴蜀定理可知:若a,b是整数,且 gcd(a,b)=d,那么对于任意的整数x,y,ax+by都一定是d的倍数,特别地,一定存在整数x,y,使 ax + by = d 成立,那么倘若 gcd(a,b) != 1 必然会有无数个数字不能被表示。

那么INF 的情况我们就已经讨论出来了

再来看看非 INF 的情况,即  gcd(a,b) = 1

若 a , b 互质,那么任何大于 a * b 的数都可以表示为 k1 * a + k2 * b 

因此当 ai <= 100 时,大于 10000 的数都可以被表示,我们只需要对 10000 以内的数判断一下就好了

状态转移 

完全背包

f[i]表示 数i 能被 f[i]种方式表示 若f[i] = 0 那么就是不能被表示的

  f[0] = 1;
    for(int i = 1;i <= n;i ++)//枚举 i 种不同的笼子
     for(int j = 1;j <= 10010;j ++)//枚举 1 ~ 10000 这些数
     {
        if(j - a[i] >= 0 && f[j - a[i]] >= 1) f[j] ++;//倘若 j-a[i] 可以被表示 那么j一定可以被表示
     }

Java

import java.util.Scanner;

public class Main
{
    static int f[] = new int[10100];
    static int a[] = new int[10100];
    public static int gcd(int a,int b)
    {
        if(b != 0) return gcd(b,a % b);
        else return a;
    }
    public static void main(String args[])
    {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        for(int i = 1;i <= n;i ++)
        a[i] = in.nextInt();
        in.close();
        int tmp = a[1];
        for(int i = 2;i <= n;i ++)
        tmp = gcd(tmp,a[i]);
        
        if(tmp != 1)
        {
            System.out.printf("INF");
            return ;
        }
        else 
        {
            f[0] = 1;
            for(int i = 1;i <= n;i ++)
             for(int j = 0;j <= 10010;j ++)
              if((j - a[i] >= 0) && (f[j - a[i]] != 0)) f[j] ++;
            
            int cnt = 0;
            for(int i = 1;i <= 10010;i ++) if(f[i] == 0) cnt ++;
            
            System.out.printf("%d\n",cnt);
        }
        return ;
    }
}

 C ++

#include<bits/stdc++.h>
using namespace std;
const int N = 20000;

int f[N],a[N];

int gcd(int a,int b)
{
    return b ? gcd(b,a % b) : a;
}

int main()
{
    int n; cin >> n;
    for(int i = 1;i <= n;i ++) cin >> a[i];
    
    int tmp = a[1];
    
    for(int i = 2;i <= n;i ++)
    {
        tmp = gcd(tmp,a[i]);
    }
    //cout << tmp << endl;
    
    if(tmp != 1) 
    {
        puts("INF");
        return 0;
    }
    else 
    {
        f[0] = 1;
        for(int i = 1;i <= n;i ++)
         for(int j = 1;j <= 10010;j ++)
         {
             if(j - a[i] >= 0 && f[j - a[i]] >= 1) f[j] ++;
         }
    }
    int cnt = 0;
    for(int i = 1;i <= 10010;i ++)
    {
        if(f[i] == 0) cnt ++;  
    }
    cout << cnt << endl;
    return 0;
}

2018 年 省赛 填空题 分数

题目链接

答案: 1048575 / 524288

等比数列求和即可,没啥可写的

2018 年 省赛 填空题 星期一

题目链接

答案: 5217

以今天是2022/1/25日 星期二为例求解此题

找到最近的星期一 2022/1/24 日

计算1901年1月1日 至 2022年1月24日 有多少天,求得是 44219 天,

那么再计算1901年1月1日 至2000年12月31日有多少天,求得是 36525 天

那么只要从第一天开始枚举是否和 44219对 7 同余就行了

for(int i = 1;i <= 36525;i ++)
    {
        if(i % 7 == 44219 % 7) res ++;
    }

2018 年 省赛 填空题 乘积尾零

题目链接

要想凑出一个 0 就需要一个因子 2 和因子 5 那么就对所有的数枚举 2,5 的因子个数,输出较小的那个就行了,因为要两个搭配才能出 0

#include<bits/stdc++.h>
using namespace std;

int main()
{
    int er = 0,wu = 0;
    for(int i = 1;i <= 10;i ++)
     for(int j = 1;j <= 10;j ++)
      {
          int x;
          cin >> x;
          while(x % 2 == 0 || x % 5 == 0)
          {
              if(x % 2 == 0)
              {
                  x /= 2;
                  er ++;
              }
              else if(x % 5 == 0)
              {
                  x /= 5;
                  wu ++;
              }
          }
      }
    cout << min(er,wu) << endl;
    
    return 0;
}

2018 年 省赛 填空题 第几个幸运数字

题目链接

答案: 1905

算法分析

暴力枚举仅有 3,5,7 这些因子的数,再利用 set 去重计数 即可

AC code

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
set<LL> s;
const LL N = 59084709587505;
LL qmi(LL a, LL k)
{
    LL res = 1;
    while (k)
    {
        if (k & 1) res = (LL)res * a;
        a = (LL)a * a;
        k >>= 1;
    }
    return res;
}

int main()
{
    LL num;
    for(int i = 0;i < 50;i ++)
     for(int j = 0;j < 50;j ++)
      for(int k = 0;k < 50;k ++)
       {
           num = qmi(3,i) * qmi(5,j) * qmi(7,k);
           if(num > 1 && num <= N) s.insert(num);
       }
    cout << s.size() << endl;
    return 0;
}

2018 年 省赛 代码填空题 打印图形

题目链接

答案: n = size / 3

AC code

#include <stdio.h>
#include <stdlib.h>

void show(char* buf, int w){
    int i,j;
    for(i=0; i<w; i++){
        for(j=0; j<w; j++){
            printf("%c", buf[i*w+j]==0? ' ' : 'o');
        }
        printf("\n");
    }
}

void draw(char* buf, int w, int x, int y, int size)// 9 4 4 9
{
    if(size==1){
        buf[y*w+x] = 1;
        return;
    }
    //w => 每一行有多少个元素 
    //y => 当前在第几行
    //x => 当前在第几列
    //size = 9
    //9 4 4 n
    //9 4-n 4 n
    int n = size / 3 ; //填空
    draw(buf, w, x, y, n);
    draw(buf, w, x-n, y ,n);
    draw(buf, w, x+n, y ,n);
    draw(buf, w, x, y-n ,n);
    draw(buf, w, x, y+n ,n);
}

int main()
{
    int N ;
        scanf("%d",&N);
    int t = 1;
    int i;
    for(i=0; i<N; i++) t *= 3;
    
    char* buf = (char*)malloc(t*t);
    for(i=0; i<t*t; i++) buf[i] = 0;
    
    draw(buf, t, t/2, t/2, t);//draw(buf,9,4,4,9)
    show(buf, t);
    free(buf);
    
    return 0;
}

2018 年 省赛 航班时间

题目链接

算法分析

字符串大模拟,注意字符串读入的一些操作

C ++

#include<bits/stdc++.h>
using namespace std;

int time()
{
    char s[100];
    cin.getline(s,30);
    int h1,m1,s1,h2,m2,s2,k = 0;//注意 k 的初始化
    if(strlen(s) <= 17) sscanf(s,"%d:%d:%d %d:%d:%d",&h1,&m1,&s1,&h2,&m2,&s2);
    else sscanf(s,"%d:%d:%d %d:%d:%d (+%d)",&h1,&m1,&s1,&h2,&m2,&s2,&k);
    //printf("%d:%d:%d %d:%d:%d\n",h1,m1,s1,h2,m2,s2);
    return ((k * 24 + h2 - h1) * 3600 + (m2 - m1) * 60 + (s2 - s1));
}

void solve()
{
    int t1 = time();
    int t2 = time();
    int res = (t1 + t2) / 2;
    //printf("t1 = %d t2 = %d",t1,t2);
    int h = res / 3600;
    int m = res % 3600 / 60;
    int s = res % 3600 % 60;
    printf("%02d:%02d:%02d\n",h,m,s);
}
int main()
{
    int T;
    cin >> T;
    getchar();//注意把回车给吃了
    while(T --)
    solve();
    return 0;
}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Cold啦啦啦

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

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

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

打赏作者

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

抵扣说明:

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

余额充值