2013年省赛题

题目列表

  1. 猜年龄
  2. 组素数
  3. 马虎的算式
  4. 第39阶台阶
  5. 有理数类
  6. 逆波兰表达式
  7. 核桃的数量
  8. 打印十字架
  9. 买不到的数目
  10. 剪格子(未做)

一、猜年龄

答案:18
美国数学家维纳智力早熟,11岁就上了大学。他曾在1935~1936年应邀来中国清华大学讲学。
一次,他参加某个会议,年轻的脸引人注目。于是有人询问他的年龄,他回答说:“我年龄的立方是个4位数。我年龄的4次方是个6位数。这10位数字正好包含了从0到9这10个数字,每个都恰好出现1次。”
请你推算一下,他当时到底有多年轻。
通过浏览器,直接提交他那时年龄数字。
注意:不要提交解题过程,或其他的说明文字。

思路:
首先,这题运用了set集合,用于去掉重复的数字,通过for循环,遍历0~9之间的数字补充去掉的空位,如果set.size(集合的大小)等于10则返回true

解题方法:
假设他的年龄在11到100之间,通过for循环遍历,求出每个数字的三次方和四次方,再把这两个数字转化位字符串,如果存储三次方数字的字符串长度等于4 && 存储四次方数字的字符串长度等于 6 && 这两个字符串合并后没有重复的字符,那么输出对应的年龄

代码块:

//导入包
import java.util.HashSet;
import java.util.Set;
public class GuessAge {
 public static void main(String[] args){
   
  for(int i = 11; i < 100; i++){
   int t1 = i*i*i;
   int t2 = t1*i;
   String s1 = t1 + "";
   String s2 = t2 + "";
      
   if(s1.length() == 4 && s2.length() == 6 && check(s1+s2)){
    System.out.println(i);
   }
   }
   }
    
 //用于判断s1和s2中的字符是否有相同的,如果有则去掉,然后再加上一个字符
 public static boolean check(String s){
  //Set的作用:去掉重复的字符(注意导包)
  Set<Character> set = new HashSet<Character>();
  //for循环:把0~9之间的每个数字添加到字符串s中
    for(int i = 0; i < s.length(); i++){
   //添加指定字符
   set.add(s.charAt(i));
  }
    
  //如果s的字符串长度等于10,放回true
  return set.size() == 10;
  }
  }

Summary: 这题涉及的一个新知识点:set集合可以去掉重复的元素;用set.add(s.charAt(i)); 添加指定元素;用set.size()返回集合大小(集合中元素的个数)

注意,除了代码可以信,其他的都是个人观点(仅供参考)!!!

二、组素数

答案:6
素数就是不能再进行等分的数。比如2 3 5 7 11等。
9 = 3 * 3 说明它可以3等分,因而不是素数。
我们国家在1949年建国。如果只给你 1 9 4 9 这4个数字卡片,可以随意摆放它们的先后顺序(但卡片不能倒着摆放啊,我们不是在脑筋急转弯)
那么,你能组成多少个4位的素数呢?
比如:1949,4919都符合要求。
请你提交:能组成的4位素数的个数,不要罗列这些素数!!!
注意:不要提交解答过程,或其他的辅助说明文字。

先说说个人的思路,再说说最标准的思路吧……

思路:
首先,题目只是要求提交能组成的4位素数的个数。所以,我们可以用一个for循环判断四位数中哪些是素数,当然四位数中的素数还是非常多的,那么我们再次判断:如果这四位数的素数中存在2 3 5 6 7 8 那么将这些素数除掉,这样得到了寥寥无几的几个只存在1 4 9数字的素数了,最后通过(你懂的)一个一个的数,嘿嘿,答案就这么来的

代码块:

public class OrganizePrime {
 public static void main(String[] args){
   
  //外层for循环,范围:min = 这四个数字组成的最小值,max = 这四个数组成的最大值
  for(int i = 1499; i <= 9941; i++){
   //flag用于表示这个四位数字是否符合要求,如果不符合,则返回false
   boolean flag = true;
      
   //这个for循环的作用:判断这个四位数是否是素数
   //(如果可以被除了自身和1之外的数字整除,表示该数字不是素数,返回false)
   for(int j = 2; j < i; j++){
    if(i % j == 0){
     flag = false;
    }
   }
      
   //如果flag不等于false,则再次对素数进行筛选
   if(flag){
    //b用于表示这个素数中是否含有除1 4 9 之外的数字,如果有,则返回false
    boolean b = true;
        
    //把素数i赋值给x,防止因为判断而导致i的值发生改变
    int x = i;
    //使用while循环,将每一位数字分离进行判断
    while(x > 0){
     //取该数字的最后一位
     int t = x % 10;
     //如果该数字的最后一位等于除了1 4 9 之外的数字,返回false,直接跳出循环
     if(t == 2 || t == 3 || t == 5 || t == 6 || t == 7 || t == 8 || t== 0){
      b = false;
      break;
     }
     //除掉数字的最后一位
     x /= 10;
    }
        
    //如果b为true,则返回符合条件的素数
    if(b){
     System.out.println(i);
    }
    }
    }
    }
    }

以上是个人敲的代码,当然做法有点赖皮。仅供参考(嘿嘿嘿)!!!
接下来我将给出这题的权威答案,代码如下:

import java.util.HashSet;
import java.util.Set;
public class OrganizePrime_Teacher {
 public static void main(String[] args){
  //求1 4 9 9 组成的素数的个数
  //考点:有重复元素的全排列+检查
    
  int[]arr = {1, 4, 9, 9};
  f(arr, 0);//引用f()
  System.out.println(set.size());//输出answer
 }
  
 
 //全排列模板;处理从k开始的排列(1 4 9 9)
 static void f(int[]arr, int k){//k:处理的位数
  //当k=4,表示前面的已经确定
  if(k == 4){
   check(arr);
  }
    
  for(int i = k; i < 4; i++){
   //交换
   int t = arr[k];
   arr[k] = arr[i];
   arr[i] = t;
   
   //通过递归,把k之后的数字搞定了
   f(arr, k+1);
   
   //交换之后,需要换回原样
   t = arr[k];
   arr[k] = arr[i];
   arr[i] = t;
  }
   }
 
 
 //去掉重复的数字
 static Set<Integer> set = new HashSet<Integer>();
 //判断数字是否是一个素数
 static void check(int[]arr){
   //得到一个四位数字x
  int x = arr[0]*1000 + arr[1]*100 + arr[2]*10 + arr[3];
  
  //使用flag判断这个四位数字是否是一个素数
  boolean flag = true;
  for(int i = 2; i < Math.sqrt(x); i++){
   if(x % i == 0){
    flag = false;
    break;
   }
  }
    
  //如果这个四位数字是素数,则set范围加一
  if(flag){
   //System.out.println(x);
   set.add(x);
  }
  }
  }

以上就是最标准的答案了,其中的知识点有:上一题的set集合去重复元素、递归、有重复元素的全排列(模板)等。
**温馨提示:**以上代码的注释是本人写的,如果有错误或者不足的地方欢迎在评论区评论,当然如果我的真的有错误的注释,碰巧你也没看出来,那就跟着一起错吧(嘿嘿嘿)……

三、马虎的算式

答案:142
小明是个急性子,上小学的时候经常把老师写在黑板上的题目抄错了。
有一次,老师出的题目是:36 * 495 = ?
他却抄成了:396 * 45 = ?
但结果却很戏剧性,他的答案竟然是对的!!
因为 36 * 495 = 396 * 45 = 17820
类似这样的巧合情况可能还有很多,比如:27 * 594 = 297 * 54
假设 a b c d e代表 1~9不同的5个数字(注意是各不相同的数字,且不含0)
能满足形如:ab * cde = adb * ce 这样的算式一共有多少种呢?
请你利用计算机的优势寻找所有的可能,并回答不同算式的种类数。
满足乘法交换律的算式为不同的种类,所以答案肯定是个偶数。
答案直接通过浏览器提交。

解决方法:
首先说句实话,我没想到这题我也能做出来,最开始看题的时候,我就是一脸懵逼的,本来想直接看微课里的代码的,但是想了想,如果不思考就直接看答案多没意思,于是我就分析了一下
发现这道题跟之前老师讲的暴力破解非常相似,本来想在这里稍微介绍一下暴力破解的,发现自己归纳的有些问题,于是我就在百度里查了一下,却发现原来暴力破解法就是枚举法可以点击蓝色字体进行简单的了解一下,大概就是利用电脑的优势对一种问题的所有情况进行挨个判断。不过后来我发现微课里的代码时间复杂度比我的要低!!不废话了,上代码:

首先是个人写的代码:

public class WrongEquation {
 public static void main(String[] args){
   long startTime = System.currentTimeMillis();
  
  int count = 0;
    for(int a = 1; a < 10; a++){
   for(int b = 1; b < 10; b++){
    for(int c = 1; c < 10; c++){
     for(int d = 1; d < 10; d++){
      for(int e = 1; e < 10; e++){
             
       if(a != b && a != c && a!= d && a!= e && 
        b != c && b != d && b != e && 
        c != d && c != e && 
        d != e){
                
        if((a*10 + b) * (c*100 + d*10 + e) == 
         (a*100 + d*10 + b) * (c*10 + e)){
         count++;
        }
        }       
      }
     }
    }
   }
  }
  
  System.out.println("count:"+count);
    long endTime = System.currentTimeMillis();
  System.out.println("程序运行时间:"+(endTime-startTime)+"ms");
  }
  }
      

以上是个人代码,接下来是权威代码:

public class WrongEquation_Teacher {
 public static void main(String[] args){
  long startTime = System.currentTimeMillis();
  
  int count = 0;
  for(int a = 1; a < 10; a++){//a
   for(int b = 1; b < 10; b++){//b
    if(a != b){
         for(int c = 1; c < 10; c++){//c
      if(c != a && c != b){
       for(int d = 1; d < 10; d++){//d
        if(d != a && d != b && d != c){
         for(int e = 1; e < 10; e++){//e
          if(e != a && e != b && e != c && e != d){
          
           if((a*10 + b) * (c*100 + d*10 + e) == 
            (a*100 + d*10 + b) * (c*10 + e)){
            count++;
           }
          }
         }
                 }
       }
      }
     }
    }
   }
  }
    
  System.out.println("count:"+count);
  
  long endTime = System.currentTimeMillis();
  System.out.println("程序运行时间:"+(endTime-startTime)+"ms");
  }
  }

在这题的最后提一下“如何获取程序运行时间”(我之前在百度里碰到的,忘记是哪个大佬的博客里的):
//放在程序最前面(如:Scanner cs = new Scanner(System.in);的下面一行)
long startTime = System.currentTimeMillis(); //获取开始时间
//放在程序的最后面
long endTime = System.currentTimeMillis(); //获取结束时间
System.out.println(“程序运行时间:” + (endTime - startTime) + “ms”); //输出程序运行时间
运行结果
对于这道题,我是没啥说的了,练习系统里的题目比这个难的一抓一大把……

第四题、第39阶台阶

答案:51167078
小明刚刚看完电影《第39阶台阶》,离开电影院的时候,他数了数礼堂前的台阶数,恰好是39级!
站在台阶前,他突然又想着一个问题:
如果我每一步只能迈上1个或2个台阶。先迈左脚,然后左右交替,最后一步是迈右脚,也就是说一共要走偶数步。
那么,上完39级台阶,有多少种不同的上法呢?
请你利用计算机的优势,帮助小明寻找答案。

要求提交的是一个整数。
注意:不要提交解答过程,或其他说明文字

思路:
1,理清题目意思:需要上39个台阶,每次可以迈1步或者2步,总步数是一个偶数;2,方法:考虑到没上一个台阶都必须考虑下一步是迈一步呢还是迈两步呢,使用递归可以完美的解决这一问题

上代码:

public class ThirtyNinthStep {
 public static void main(String[] args){
   
  //调用f方法,初始化n为台阶数量,step的初始步数为0
  f(39, 0);
  //输出全局变量ans
  System.out.println(ans);
 }
 
 //定义全局变量ans用于存储每次走法的种类
 static int ans = 0;
 //定义一个有参无返回值的方法;n为总台阶数,step为所走步数
 public static void f(int n, int step){
   //如果n小于0,表示所走步法已经全部遍历了,此时跳出方法体,输出ans
  if(n<0){
   return;
  }
  //由题意,当n==0表示上台阶的一种上法已经算出来了,step % 2 == 0表示所走的步数是偶数步
  //只有符合以上两个条件,ans(上法)加一
  if(n == 0 && step % 2 == 0){
     ans++;
  }
  //使用递归(自己调自己),算出每次上一步和上两步的上法
  f(n-1, step+1);
  f(n-2, step+1);
  }
  }

总结,这题其实我如果不看微课是不可能做出来的,当然也没想到可以用一两句代码就可以解决,但我做完了之后对于这题的了解以及对递归有了进一步的认识,虽然没有赚,但是没有亏,希望之后我可以把这题完全搞懂吧。
Personal feel: 感觉递归很抽象,个人应该还没有适应这种方法,打算在过几天在学一下递归,还有一个就是微课是以C语言代码的形式呈现问题的解法,不过思路还是听明白了一些……

五、有理数类

答案:new Rational(rax.rb + x.rarb, rb*x.rb);
(该题是一个填空题,故直接以代码形式显示)

public class YouLiShuClass {
 public static void main(String[] args){
  
  /*题目:
   * 有理数就是可以表示为两个整数的比值的数字。一般情况下,我们用近似的小数表示。
   * 但有些时候,不允许出现误差,必须用两个整数表示。
   * 这时,我们可以建立一个“有理数类”,下面的代码初步实现了这个目标。
   * 为了简明,它只提供了加法和乘法。 
   * 
   * 【大概题目意思就是,用两个数字(分子/分母)来表示两个整数的比值,
   * 下面提供了加法和乘法的公式,要求不全加法公式中的代码】
   */
     
  class Rational{ //rational: 有理数
   private long ra;
   private long rb;
      
   private long gcd(long a, long b){//gcd:最大公约数(greatest common divisor)
    if(b == 0){
     return a;
    }
    return gcd(b, a%b);
   }
      
   public Rational(long a, long b){//构造方法
    ra = a;
    rb = b;
    long k = gcd(ra, rb);
    if(k > 1){ //需要约分
     ra /= k;
     rb /= k;
    }
   }
      
   //加法
   public Rational add(Rational x){
    //return ____________________;//填空位置
    return new Rational(ra*x.rb + x.ra*rb, rb*x.rb);
   }
   //乘法
   public Rational mul(Rational x){
    return new Rational(ra*x.ra, rb*x.rb);
   }
      
   public String toString(){
    if(rb == 1){
     return ""+ra;
    }
    return ra+"/"+rb;
   }
  }
    
  //使用该类的示例:
  Rational a = new Rational(1,3);
  Rational b = new Rational(1,6);
  Rational c = a.add(b);
  System.out.println(a + "+" + b + "=" + c);
  //请分析代码逻辑,并推测划线处的代码,通过网页提交
  //注意仅把缺少的代码作为答案,千万不要填写多余的代码、符号或说明文字!!
 }
 }

思路:首先清楚题目问的问题,然后看题目代码

解决方法:可以通过类比法对横线出进行补代码;题目已经给了一个完整的乘法类的代码,要求填写残缺的加法类代码。两个分数相乘:分子分子/分母分母,然后约分(题目已经敲好了约分类的代码)。两个分数相加:把分母化为同一个数字,然后分子相加。
通过“乘法类”中的“return new Rational(rax.ra, rbx.rb);”可以得出:前一个数表示结果表达式的分子:第一个分子第二个分子;后一个数表示结果表达式的分母:第一个分母第二个分母。所以两个分数相加时,两个数字的分子分别乘以另一个数字的分母,而两个数字的分母因为是相互乘,所以相同,故只用其中的一个数的分母表示即可。最后通过分析得出答案:new Rational(rax.rb + x.rarb, rb*x.rb);

总结:这题的代码我没看懂,我只是通过进行两数相乘的这个类类比除了加法这个类的完整答案……

六、逆波兰表达式

答案:evaluate(x.substring(1+v1[1]))
事先说明:该题是一个填空题,我并没有该题的题目,所以我在抄代码的时候也把题目注释在了代码上了。
做题的时候不用计较什么逆波兰表达式,看不懂前缀表达式也没有关系,这不是重点(我才不会我还查了什么是逆波兰表达式)。该题主要是不全代码,所以只用找到对应得规律即可。
先看看填空的位置:
int[]v1 = evaluate(x.substring(1));
int[]v2 = _______________________;//填空位置
可以看到题目要求我们补全int[]v2后面的语句,而前面刚好又有一个类似int[]v2数组的int[]v1,那么可以知道里面填的是:evaluate(?);但是括号内的还不知道,这时我们看后面的代码:

  int v = Integer.MAX_VALUE;
  //判断字符c的符号,如果非数字字符,则执行对应的四则运算
  if(c == '+'){
   v = v1[0] + v2[0];
  }
  if(c == '*'){
   v = v1[0] * v2[0];
  }
  if(c == '-'){
   v = v1[0] - v2[0];

从上面的三个表达式可以知道答案是v1[0]+/*/-v2(数组v1 运算符 数组v2);那么v2数组到底是什么呢?
我们通过题目里的两个表达式:中缀表达式和前缀表达式可以知道:
3 + 5 * (2 + 6) -1

    • 3 * 5 + 2 6 1
      v1正是3 + 5 * (2 + 6)。你可能会问为什么?我们可以看到前缀表达式的第一个字符就是"-"减号,因为只有字符是运算符的时候才会执行后面的代码。
      由上面的代码可以知道:if( c== ’ - '){},再看看中缀表达式:3 + 5 * (2 + 6) -1:1的前面正是负号。所以我们可以知道,题目代码是将一个表达式分成了两个部分,那么第二个部分就是v2[]了。
      如何求出v2呢?
      通过以上分析,我们可以知道表达式中除了v1的那部分就是v2了。所以我们只需截取上一次没有处理的字符就可以了。

上代码:

public class NiBoLanBiaoDaShi {
 public static void main(String[] args){
  /*
   * 题目:逆波兰表达式
   * 正常的表达式称为中缀表达式,运算符在中间,主要是给人阅读的,机器求解并不方便。
   * 例如:3 + 5 * (2 + 6) -1
   * 而且,常常需要用括号来改变运算次序。
   * 相反,如果使用逆波兰表达式(前缀表达式)表示,上面的算式则表示为:
   * - + 3 * 5 + 2 6 1
   * 不需要括号,机器可以用递归的方法很方便地求解。
   * 为了简便,我们假设:
   * 1,只有 + - * 三种运算符
   * 2,每个运算符都是一个小于10地非负整数
   * 
   * 下面的程序对一个逆波兰表示串进行求值
   * 其返回值为一个数组:其中第一元素表示求值结果,第二个元素表示它已解析的字符数。
   */
  
  System.out.println(evaluate("-+3*5+261")[0]);
 }
  
 //这是一个有参有返回值的方法(递归!!!)
 static int[] evaluate(String x){
  //如果字符串的长度为0,即表示这是一个空字符串,则直接返回一个0,后面的代码不执行
  if(x.length() == 0){
   return new int[]{0, 0};
  }
    
  //c表示获取字符串x的第一个字符
  char c = x.charAt(0);
  //如果第一个字符是数字,那么返回这个数字,后面的代码不执行
  if(c >= '0' && c <= '9'){
   return new int[]{c-'0', 1};
  }
    
  //x.substring(1)表示从字符串的第二个字符开始,
  //把之后的全部字符(包括第二个字符)全部截取存储在int[]v1中
  int[]v1 = evaluate(x.substring(1));//第一个字符是运算符
  //int[]v2 = _______________________;//填空位置
  int[]v2 = evaluate(x.substring(1+v1[1]));//截取到上一步没有处理到的部分
  
  //Integer.MAX_VALUE: int类型的最大值(v = 2147483647)
  int v = Integer.MAX_VALUE;
  //判断字符c的符号,如果非数字字符,则执行对应的四则运算
  if(c == '+'){
   v = v1[0] + v2[0];
  }
  if(c == '*'){
   v = v1[0] * v2[0];
  }
  if(c == '-'){
   v = v1[0] - v2[0];
  }
    
  //如果符合以上全部条件,返回结果
  return new int[]{v,1+v1[1]+v2[1]};
 }
  //请分析代码逻辑,并推测划线处的代码,通过网页提交。
 //注意:仅把缺少的代码作为答案,千万不要填写多余的代码、符号或说明文字!!
 }

七、核桃的数量

看前提示:这题不建议看,不难!!!

import java.util.Scanner;
public class HeTaoDeShuLiang {
 public static void main(String[] args){
  Scanner sc = new Scanner(System.in);
  
  /*
   * 核桃的数量:
   * 小张是软件项目经理,他带领3个开发组。工作紧,今天都在加班呢。为鼓舞士气,小张打算给每个组发一带核桃:
   * 1,各组的核桃数量必须相同
   * 2,各组内必须平分核桃(当然是不能打碎的)
   * 3,尽量提供满足1,2条件的最小数量
   * 
   * 程序输出:
   * 一个整数,表示每袋核桃的数量
   * 
   * 例如:
   * 用户输入:2 4 5
   * 输出:
   * 20
   */
  
  int a = sc.nextInt();
  int b = sc.nextInt();
  int c = sc.nextInt();
    
  for(int i = a; i <= a*b*c; i++){
   if(i % a == 0&& i % b == 0 && i % c == 0){
    System.out.println(i);
    break;
   }
  }
  
  }
  }
 

这题我敢说,我的代码运行效率比你的好那么一丢丢

八、打印十字架

先说说个人对于这道题的感受吧!第一次遇到这道题是在蓝桥杯的练习系统里,我当时也是第一次遇到这种题,懵了好一会儿,后来自己真的做不会于是求出某位在csdn上的大佬(忘记是谁了),思路清晰,等我看明白了,我才发现这题原来如此的简单啊!!于是我又独自做了一遍便继续我的刷题之路,过了四五天的时间,我在刷真题的时候又遇到了这道题,二话不说我直接做了出来,但我做出来的时候,我太几把激动了,因为我觉得我发现了一些新的规律。后来看微课的时候,看见讲题的老师,不是这里出问题就是那里出问题,而且把问题讲的那么复杂,我是笑着看完的……等我把那三个视频”看完“后,我就把我自己刚做好的代码放到练习系统里再次看一下是不是对的。然后:
0分!!!
等我看到这个分数的时候,才发现还是我太年轻了,遇到一点小成功就激动的不行。于是我又花了几十分钟的时间在做了一下,这次的成绩是:
100分了。
所以呢,我觉得作题还是需要保持一个平稳的心态以及认真作题的态度,不能因为代码的一点小成功而失去全部!!!

思路:
2013年省赛题_第1张图片2013年省赛题_第2张图片

由上图可知一下信息:
1,用户输入一个数字,系统应该输出一个正方形。
2,用户输入的数字是多少,那么该十字架外围的圈数就有几圈
3,当用户输入1时,得到一个边长为5的正方形;当用户输入3时,得到一个边长为17的正方形;
则:m(边长)=n(用户输入的数字)4 + 5;【一元二次方程:x = y4+5(你懂的)】
4,每个 符 号 的 排 列 都 是 有 规 律 的 , 所 以 想 到 使 用 递 归 哦 综 合 以 上 信 息 , 得 到 一 下 思 路 : 创 建 一 个 二 维 数 组 , 因 为 需 要 的 打 印 一 个 正 方 形 , 所 以 行 和 列 都 是 用 户 输 入 的 数 字 。 其 次 , 整 个 图 形 中 除 了 点 " . " 就 是 d o l l a r 符 号 " 符号的排列都是有规律的,所以想到使用递归哦 综合以上信息,得到一下思路: 创建一个二维数组,因为需要的打印一个正方形,所以行和列都是用户输入的数字。其次,整个图形中除了点"."就是dollar符号" 使"."dollar"",所以我们可以在创建数组的时候,将数组的全部元素设置为点,然后再把对应位子替换为dollar符号就可以了。(想到了吗?有感觉了吗?没错)
接下来就是替换操作了哦,(前方高能)因为是上下对称的,所以我们可以分开替换,如:先把第一行和最后一行换了,再把第二行和倒数第二行换了,然后在把第三行和倒数第三行换了,最后把边边给换了,这样就得到了最外层的图形。因为最里层的十字架是不变的,所以另外替换。
接下来是里面的了,注意每层图形都是一样的一样的一样的,且图形之间的距离是1,所以使用递归的时候,外层到内层的变化量是2(你懂的)。注意:递归最忌讳的就是没有边界,也就是出口,在写完递归的最后,需要加一个判断条件:如果图形边长小于等于0了或者图层大于图形边长的一半再减4,那么说明此时已经替换完成了,也就是到了输出的时刻了……
当然如果看完了还是不明白,没关系,代码比上面的丑文字更香……

import java.util.Scanner;
public class OutputShiZiJia {
 static int m;//定义一个全局变量
 public static void main(String[] args){
 Scanner sc = new Scanner(System.in);
  //n*4+5
  m = sc.nextInt();//接收用户输入的层数
  m = m*4+5;//把层数转化为边长
  char[][]arr = new char[m][m];//定义一个二维数组,长度m
  for(int i = 0; i < m; i++){
   for(int j = 0; j < m; j++){
    arr[i][j] = '.';//通过两个for循环给整个数组都存储一个点
   }
  }
    
  int start = 0; int end = m - 1;//定义两个变量,分别表示数组中的位置
  	//wai:替换层
  wai(arr, start, end);
  //替换十字架
  shi(arr, start, end);
  
  //打印输出
  for(int i = 0; i < m; i++){
   for(int j = 0; j < m; j++){
    System.out.print(arr[i][j]);
   }
   System.out.println();
  }
 }
  
  //这是递归,用于替换外层的dollar符号
 static void wai(char[][]arr, int start, int end){
  //出口!!!用于判断是否替换完成
  if(end <= 0 || start > m /2-4){
   return;
  }
    
  //第一行和最后一行
  for(int i = start+2; i < end-1; i++){
   arr[start][i] = '$';
   arr[end][i] = '$';
  }
  
  //第二行和倒数第二行
  arr[start+1][start+2] = '$';
  arr[end-1][start+2] = '$';
  arr[start+1][end-2] = '$';
  arr[end-1][end-2] = '$';
    
  //第三行和倒数第三行
  for(int i = 0; i < 3; i++){
   arr[start+2][start+i] = '$';
   arr[start+2][end-i] = '$';
   arr[end-2][start+i] = '$';
   arr[end-2][end-i] = '$';
  }
  
  //边
  for(int i = start+2; i < end-2; i++){
   arr[i][start] = '$';
   arr[i][end] = '$';
  }
    
  wai(arr, start+2,end-2);
 }
 //用于替换最里层的十字架
 static void shi(char[][]arr, int start, int end){
  //横
    arr[m/2][m/2+2] = '$';
  arr[m/2][m/2+1] = '$';
  arr[m/2][m/2] = '$';
  arr[m/2][m/2-1] = '$';
  arr[m/2][m/2-2] = '$';
  //竖
  arr[m/2-1][m/2] = '$';
  arr[m/2-2][m/2] = '$';
  arr[m/2+1][m/2] = '$';
  arr[m/2+2][m/2] = '$';
  }
  }

最后如果不知道题目的要么私聊要么蓝桥杯练习系统题目所在的链接点击左边链接
这题不难,虽然代码比较多,但是思路清晰了,做完也是一口气的事情啦

九、买不到的数目

这题在练习系统里也有,所以我就把练习系统里的题目copy过来:
问题描述

小明开了一家糖果店。他别出心裁:把水果糖包成4颗一包和7颗一包的两种。糖果不能拆包卖。
小朋友来买糖的时候,他就用这两种包装来组合。当然有些糖果数目是无法组合出来的,比如要买 10 颗糖。
你可以用计算机测试一下,在这种包装情况下,最大不能买到的数量是17。大于17的任何数字都可以用4和7组合出来。
本题的要求就是在已知两个包装的数量时,求最大不能组合出的数字。

输入格式

两个正整数,表示每种包装中糖的颗数(都不多于1000)

输出格式

一个正整数,表示最大不能买到的糖数

样例输入1

4 7

样例输出1

17

样例输入2

3 5

样例输出2

7

这题如果思路有了,其实也不难的。

思路:
1,初步了解Java中的set方法以及语法
你知道Java中有一个set方法吗?不知道?没关系,set是Java里的一个集合方法,集合知道吗,没错就是你在高中一年级第一课学的集合,集合有三个特点,其中一个就是:唯一性!也就是说set中的每个元素都是不同的。现在知道set方法了,那我们就聊聊其中有哪些语法吧:点我!点我!!点我!!!当你点开链接后,可以发现set中有一个语法是:contains( ) //判断集合中是否包含某一个元素。先别问为什么要提这个语法,我现在是不会告诉你接下来是要用到的。
2,解题的思路:
首先理解一下题目要求:输入两个正整数,输出一个整数ans。ans的条件:
1,是用户输入的两个整数无法组合的;例如:用户输入3和5,那么7这个数字无论如何3和5都无法组成,因为3和5组成的数有:3, 5, 8(3+5), 11(3+3+5),13(5+5+3)……。
2,要求这个ans是最大的,也就是说,ans以后的每个数字用户输入的两个数字都可以组成
那么现在我们可以把那些可以被组合的数字都放进集合set中,然后通过某范围的遍历,判断集合set中那些数字没有!那么这些没有的数字就是那些不能被组合的数字,对不对!!!在这些不能被组合的数字当中的最大值就是答案ans了!(惊不惊喜意不意外)如果你看了三遍我写的思路还不觉得我写的花里胡哨的,没关系,上代码,个人的代码知识了解的不多,都是基础的,相信你可以看懂一位小白写的代码:

上代码:

import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class BuyNotNum {
 public static void main(String[] args){
  Scanner sc = new Scanner(System.in);
    
  int a = sc.nextInt();//4
  int b = sc.nextInt();//7
   
  //set集合
  Set<Integer> set = new HashSet<Integer>();
  for(int j = 1; j <= Math.max(a, b); j++){
   set.add(j*a);
   set.add(j*b);
  }
    
  for(int i = 1; i < Math.max(a, b); i++){
   for(int j = 1; j < Math.max(a, b); j++){
    set.add(i*a+j*b);
   }
  }
    
  int max = 0;
  for(int i = Math.max(a, b); i < a*b; i++){
   
   boolean x = set.contains(i);
   if(!x){
    if(i > max){
     max = i;
    }
   }
  }
    
  System.out.println("max:"+max);
  }
  }

另外这题还有另一种解法,(前方高能)这种解法我保证你会有种吐血的感觉,如果你没想到的话:

import java.util.Scanner;
public class Main {
 public static void main(String[] args){
  Scanner sc = new Scanner(System.in);

  int a = sc.nextInt();//4
  int b = sc.nextInt();//7
  System.out.println((a*b) - (a+b));
  
 }
}

这是上一个代码的评测结果
你没有看错,这题,这个真题,这个代码题,完美解法只需10行不到的代码就可以得满分!
!当然这不是我想到的,我的数学不咋地,这是我看微课里的老师讲的,真尼玛牛逼!对于这个10行代码我就不多说了说多了都是泪呀。(这是一种境界,妙不可言的那种)

十、剪格子

如图p1.jpg所示,3 x 3 的格子中填写了一些整数。

我们沿着图中的红色线剪开,得到两个部分,每个部分的数字和都是60。

本题的要求就是请你编程判定:对给定的m x n 的格子中的整数,是否可以分割为两个部分,使得这两个区域的数字和相等。
如果存在多种解答,请输出包含左上角格子的那个区域包含的格子的最小数目。
如果无法分割,则输出 0

程序输入输出格式要求:
程序先读入两个整数 m n 用空格分割 (m,n<10)
表示表格的宽度和高度
接下来是n行,每行m个正整数,用空格分开。每个整数不大于10000
程序输出:在所有解中,包含左上角的分割区可能包含的最小的格子数目。

例如:
用户输入:
3 3
10 1 52
20 30 1
1 2 3

则程序输出:
3

再例如:
用户输入:
4 3
1 1 1 1
1 30 80 2
1 1 1 100

则程序输出:
10

(参见p2.jpg)

资源约定:
峰值内存消耗(含虚拟机) < 64M
CPU消耗 < 5000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.6及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。

你可能感兴趣的:(省赛题之JavaC组)