蓝桥杯历届省赛真题题解(6到14届)
本文最后更新于859 天前,其中的信息可能已经过时,如有错误请评论留言

第六届 省赛(真题课件14)

  1. 隔行变色

    Excel 表的格子很多,为了避免把某行的数据和相邻行混淆,可以采用隔行变色的样式小明设计的样式为:第 1行蓝色,第 2 行白色,第 3 行蓝色,第 4行白色,....现在小明想知道,从第 21 行到第 50 行一共包含了多少个蓝色的行.

    答案:15

  2. 立方尾不变

    有些数字的立方的末尾正好是该数字本身.
    比如: 1,4,5,6,9,24,25,....
    请你计算一下,在 10000 以内的数字中 (指该数字,并非它立方后的数值),符合这个特征的正整数一共有多少个.

    public class LiFangWeiBuBian {
       public static void main(String[] args) {
           int count = 0;
           for(long i=1;i <10000;i++){
               String str = i*i*i + "";
               String si = i + "";
               if(str.endsWith(si)){
                   count++;
               }
           }
           System.out.println(count);
       }
    }

    答案:36

  3. 无穷分数

    无穷的分数,有时会趋向于固定的数字.请计算图所示的无穷分数,要求四舍五入,精确到小数点后 5 位,小数位不足的补0.

    public class WuQiongFenShu {
       public static void main(String[] args) {
           double i = 1000;
           double sum = i + 2;
           for(;i >= 0;i--) sum = i + (i + 1) / sum;
           System.out.printf("%.5f",sum);
       }
    }

    答案:0.58198

  4. 循环节长度

    两个整数做除法,有时会产生循环小数,其循环部分称为: 循环节比如,11/13=6=>0.846153846153..... 其循环节为[846153] 共有 6 位下面的方法,可以求出循环节的长度.
    请仔细阅读代码,并填写划线部分缺少的代码.

    public static int f(int n,int m){
       n = n % m;
       Vector v = new Vector();
       for(;;){
           v.add(n);
           n *= 10;
           n = n % m;
           if(n == 0) return 0;
           if(v.indexOf(n) >= 0) return v.size() - v.indexOf(n);
       }
    }

    答案:return v.size() - v.indexOf(n);

  5. 格子中输出

    stringInGrid 方法会在一个指定大小的格子中打印指定的字符串要求字符串在水平、垂直两个方向上都居中。如果字符串太长,就截断.如果不能恰好居中,可以稍稍偏左或者偏上一点。
    下面的程序实现这个逻辑,请填写划线部分缺少的代码.

    public static void stringInGrid(int width, int height, String s) {
       if (s.length() > width - 2) s = s.substring(0, width - 2);
       System.out.print("+");
       for (int i = 0; i < width - 2; i++) System.out.print("-");
       System.out.println("+");
       for (int k = 1; k < (height - 1) / 2; k++) {
           System.out.print("|");
           for (int i = 0; i < width - 2; i++) System.out.print(" ");
           System.out.println("|");
       }
       System.out.print("|");
       String ff = "%" + ((width - 2 - s.length()) / 2) + "s%s%" + ((width - 1 - s.length()) / 2) + "s";
       System.out.print(String.format(ff, "", s, ""));
       System.out.println("|");
       for (int k = (height - 1) / 2 + 1; k < height - 1; k++) {
           System.out.print("|");
           for (int i = 0; i < width - 2; i++) System.out.print(" ");
           System.out.println("|");
       }
       System.out.print("+");
       for (int i = 0; i < width - 2; i++) System.out.print("-");
       System.out.println("+");
    }

    答案:"%" + ((width - 2 - s.length()) / 2) + "s%s%" + ((width - 1 - s.length()) / 2) + "s";

  6. 奇妙的数字

    小明发现了一个奇妙的数字.它的平方和立方正好把 0~9 的 10 个数字每个用且只用了一次你能猜出这个数字是多少吗?
    请填写该数字,不要填写任何多余的内容.

    public class QiMiaoDeShuZi {
    public static void main(String[] args) {
        char[]  nums = {'0','1','2','3','4','5','6','7','8','9'};
        for(int i = 30;;i++) {
            char[] num = (i*i + "" + i*i*i).toCharArray();
            Arrays.sort(num);
            if(i == 100) break;
            if(Arrays.equals(nums, num)) {
                System.out.println(i);
                break;
            }
        }
    }
    }

    答案:69

  7. 加法变乘法

    我们都知道: 1+2+3+ ... + 49 = 1225
    现在要求你把其中两个不相邻的加号变成乘号,使得结果为 2015
    比如:
    1+2+3+...+1011+12+...+2728+29+...+49 = 2015就是符合要求的答案。
    请你寻找另外一个可能的答案,并把位置靠前的那个乘号左边的数字提交(对于示例,就是提交 10).
    注意: 需要你提交的是一个整数,不要填写任何多余的内容.

    public class JiaFaBianChengFa {
    public static void main(String[] args) {
          int num = 2015 - 1225;
          for(int i = 2;i<50;i++){
              for(int j = i+2;j<50;j++){
                  if(i*(i-1)+j*(j-1)-(i+i-1+j+j-1)==num){
                      if((i-1)!= 10){
                          System.out.println(i-1);
                          break;
                      }
                  }
              }
          }
      }
    }

    答案:16

  8. 移动距离

    X 星球居民小区的楼房全是一样的,并且按矩阵样式排列。其楼房的编号为 1,2,3..当排满一行时,从下一行相邻的楼往反方向排号.比如: 当小区排号宽度为 6 时,开始情形如下:
    1 2 3 4 5 6
    12 11 10 9 8 7
    13 14 15 .....
    我们的问题是:已知了两个楼号 m 和 n,需要求出它们之间的最短移动距离(不能斜线方向
    输人为3 个整数 w m n,空格分开,都在1到 10000 范围内要求输出一个整数,表示 m n 两楼间最短移动距离。

    public class YiDongJvLi {
    public static void main(String[] args) {
        System.out.println("请输入:");
        Scanner input = new Scanner(System.in);
        int length = input.nextInt();
        int one = input.nextInt();
        int two = input.nextInt();
    
        int ox = one / length;
        int oy = one % length;
        int tx = two / length;
        int ty = two % length;
    
        if (one % length == 0) {
          oy = length;
        } else {
          ox = ox + 1;
        }
        if (two % length == 0) {
          ty = length;
        } else {
          tx = tx + 1;
        }
        if (ox % 2 == 0) {
          oy = length - oy + 1;
        }
        if (tx % 2 == 0) {
          ty = length - ty + 1;
        }
        System.out.println(Math.abs(ox - tx) + Math.abs(oy - ty));
      }
    }
  9. 打印大X

    小明希望用星号拼凑,打印出一个大 X,他要求能够控制笔画的宽度和整个字的高度.
    为了便于比对空格,所有的空白位置都以句点符来代替。
    要求输入两个整数 m n,表示笔的宽度,X 的高度。用空格分开(0<m<n,3<n<1000,保证是奇数)
    要求输出一个大 X

    public class DaYinDaX {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        //接收高度和宽度
        int n=sc.nextInt();
        int m=sc.nextInt();
        sc.close();
        //初始化二维数组
        char[][] ch=new char[n][n+m-1];
        for(int i=0;in-2-i;j--)
            {
                //空格不需要处理,处理*号
                ch[i][j]='*';
            }
        }
    
        for(int i=0;i

    备注:运行时输入 X 的高和宽,和第九届第六题一样

  10. 垒骰子

    赌圣 atm 晚年迷恋上了散子,就是把散子一个垒在另一个上边,不能歪歪扭扭,要垒成方柱体。
    经过长期观察,atm 发现了稳定骰子的奥秘:有些数字的面贴着会互相排斥!我们先来规范一下散子: 1 的对面是 4,2 的对面是 5,3 的对面是 6.假设有 m 组互斥现象,每组中的那两个数字的面紧贴在一起,骰子就不能稳定的垒起来atm 想计算一下有多少种不同的可能的垒骰子方式。两种垒散子方式相同,当且仅当这两种方式中对应高度的骰子的对应数字的朝向都相同.由于方案数可能过多,请输出模 10^9 + 7 的结果

    public class LeiTouZi {
    static final int mod=1000000000+7;
    
        static long mypow(int x,int y) {
            long res=1;
            for(int i=1;i<=y;i++) {
                res*=x;
            }
            return res;
        }
    
        public static void main(String[] args) {
            Scanner reader=new Scanner(System.in);
            //n个骰子
            int n=reader.nextInt();
    
            int m=reader.nextInt();
            //对立面
            int [] op=new int[] {0,4,5,6,1,2,3};
    
            //m组互斥对
            boolean [][] confilct=new boolean[7][7];
            for(int i=0;i

    备注:同上题,运行时先输入,详见题目测试用例。(太难了,建议放弃跳过)

    题目链接:https://www.lanqiao.cn/courses/2786/learning/?id=67114&compatibility=false (需要登录)


第七届 省赛(真题课件41)

  1. 有奖猜谜

    小明很喜欢猜谜语。最近,他被邀请参加了 X 星球的猜谜活动
    每位选手开始的时候都被发给 777 个电子币规则是:猜对了,手里的电子币数目翻倍,猜错了,扣除 555 个电子币,扣完为止.
    小明一共猜了 15 条谜语.战果为: VXVXVXVXVXVXVVX其中v 表示猜对了,x 表示猜错了.
    请你计算一下,小明最后手里的电子币数目是多少

    public class YouJiangCaiMi {
    public static void main(String[] args){
           String s = "vxvxvxvxvxvxvvx";
           long m = 777;
    
           for(int i = 0;i

    答案:58497

  2. 煤球数目

    有一堆煤球,堆成三角棱形。具体:
    第一层放 1 个,
    第二层 3 个(排列成三角形),
    第三层 6 个 (排列成三角形),第四层 10 个 (排列成三角形),
    如果一共有 100 层,共有多少个煤球?

    public class MeiQiuShuMu {
    public static void main(String[] args) {
           int i, n = 0, s = 0;//s表示总数,n表示每一层的数目,i表示层数
           for (i = 1; i <= 100; i++) {
               n += i;
               s += n;
           }
           System.out.println(s);
       }
    }

    答案:171700

  3. 平方怪圈

    如果把一个正整数的每一位都平方后再求和,得到一个新的正整数对新产生的正整数再做同样的处理.
    如此一来,你会发现,不管开始取的是什么数字最终如果不是落入 1,就是落入同一个循环圈.
    请写出这个循环圈中最大的那个数字.

    public class PingFangGuaiQuan {
    public static void main(String[] args) {
        int n=56;
        int max=0;
        int a=0;
        int num=0;
        for(int i=1;i<200;i++) {
            a=0;
            while(n>0) {            
                num=n%10;
                a+=num*num;
                n=n/10;
            }
            n=a;
            if(a>max)max=a;
        }
        System.out.println(max);
    }
    }

    答案:145

  4. 骰子游戏

    我们来玩一个游戏同时掷出 3 个普通骰子 (6 个面上的数字分别是 1~6).如果其中一个最子上的数字等于另外两个的和,你就赢了。
    下面的程序计算出你能获胜的精确概率 (以既约分数表示)

    public class TouZiYouXi {
    public static void main(String[] args) {
        int n = 0;
        for(int i=0; i<6; i++)
        for(int j=0; j<6; j++)
        for(int k=0; k<6; k++){
            if(i==j+k+1||j==i+k+1||k==j+i+1) n++;   //填空位置
        }
        int m = gcd(n,6*6*6);
        System.out.println(n/m + "/" + 6*6*6/m);
    }
    public static int gcd(int a, int b)
    {
        if(b==0) return a;
        return gcd(b,a%b);
    }
    }

    答案:i==j+k+1||j==i+k+1||k==j+i+1

  5. 分小组

    9 名运动员参加比赛,需要分 3 组进行预赛有哪些分组的方案呢?
    我们标记运动员为 A,B,C....I下面的程序列出了所有的分组方法。

    public class FenXiaoZu {
    public static String remain(int[] a)
    {
        String s = "";
        for(int i=0; i

    答案:s+" "+(char)(i+'A')+(char)(j+'A')+(char)(k+'A')+" "+remain(a)

  6. 凑算式

    这个算式中 A~I 代表 1~9 的数字,不同的字母代表不同的数字
    比如:
    6+8/3+952/714 就是一种解法5+3/1+972/486 是另一种解法
    这个算式一共有多少种解法?

    public class CouSuanShi {
    static boolean k[]=new boolean[10];  //判断这个数有没有被取过
     static int g[]=new int[10];//存放9个数
     static int count=0;
     public static void main(String args[])
     {
          ff(1);
          System.out.println(count);
     }
     public static void ff(int m)
     {
         if(m==10){
            if(check())count++;
         }
         for(int i=1;i<=9;i++)
         {
             if(k[i]==false)
             {
                 k[i]=true;    //回溯法
                 g[m]=i;
                 ff(m+1);
                 k[i]=false;
             }
         }
     }
     public static boolean check()  //检验是不是为10
     {
         double q=g[1];
         double w=g[2]*1.00/g[3];
         double e=(g[4]*100+g[5]*10+g[6])*1.00/(g[7]*100+g[8]*10+g[9]);
         if(q+w+e==10.00)return true;
         else return false;
     }
    }

    答案:29

  7. 冰雹数

    任意给定一个正整数 N
    如果是偶数,执行: N/2
    如果是奇数,执行: N* 3 + 1
    生成的新的数字再执行同样的动作,循环往复.
    通过观察发现,这个数字会一会儿上升到很高一会儿又降落下来,就这样起起落落的,但最终必会落到“1"这有点像小冰雹粒子在冰雹云中翻滚增长的样子
    比如N=9
    9,28,14,7,22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1可以看到,N=9 的时候,这个“小冰雹”最高冲到了 52 这个高度

    public class BingBaoShu {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        long N = sc.nextLong(); long max = 0;
        long[] arr = new long[1000001];
        for(int i = 1; i <= N; i += 2) {
            long temp = i;
            while(temp != 1) {
                if(temp <= 1E6 && arr[(int) temp] != 0)
                    break;
                if((temp & 1) == 1) {
                    temp = (temp * 3) + 1;
                    max = Math.max(temp, max);
                }else {
                    temp /= 2;
                }
    
                if(temp == 1)
                    arr[i] = max;
            }
        }
        System.out.println(max);
    
        sc.close();
    }
    }

    测试用例:case 1:输入:10,输出:52;case 2:输入:100,输出:9232

  8. 四平方和

    四平方和定理,又称为拉格朗日定理:每个正整数都可以表示为至多 4 个正整数的平方和如果把 0 包括进去,就正好可以表示为 4 个数的平方和
    比如:
    5 = 0^2 + 0^2 + 12 + 2^2
    7 = 1^2 + 1^2 + 12 + 2^2
    (^符号表示乘方的意思)
    对于一个给定的正整数,可能存在多种平方和的表示法.要求你对 4 个数排序:
    0<= a <= b<= c <= d
    并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法
    程序输人为一个正整数 N(N<5000000)要求输出 4 个非负整数,按从小到大排序,中间用空格分开

    public class SiPingFangHe {
    //存放 四平方和的数字
    public static int[] tmp = new int[4];
    //找到第一个后,标识一下
    public static boolean flg;
    public static void main(String[] args) {    
        Scanner sc = new Scanner(System.in);
        //循环输入
        while(sc.hasNextInt()) {
            int input = sc.nextInt();
            //求出它的 算术平方根
            int n = (int) Math.sqrt(input);
            //由于 flg 是个静态成员变量,所以在这里初始化下
            flg = false;
            //开始 递归寻找 数字
            dfs(0,input,n);
            System.out.println(tmp[0]+" "+tmp[1]+" "+tmp[2]+" "+tmp[3]);
        }   
    }
    
    private static void dfs(int depth, int input, int n) {
        //找到了 4 个数
        if(depth == 4) {
            //检查 四平方 和 是不是 等于 input
            if(check(input)) {
                //排升序
                Arrays.sort(tmp);
                //标记下
                flg = true;
            }
            return;
        }
        //如果有一次递归进来标记是 true,表示已经找到了,直接返回
        if(flg == true) {
            return;
        }
        //循环尝试 0 - n 的数字
        for(int i = 0; i <= n; i++) {
            //判断找到第一组没有
            if(flg == true) {
                return;
            }else {
                //将这个数字 放到 tmp 中去
                tmp[depth] = i;
                //递归寻找下一个数字
                dfs(depth+1,input,n);
            }
        }
    }
    
    private static boolean check(int input) {
        int ret = (int) (Math.pow(tmp[0], 2)+Math.pow(tmp[1], 2)+Math.pow(tmp[2], 2)+Math.pow(tmp[3], 2));
        if(ret == input) {
            return true;
        }
        return false;
    }
    }

    测试用例:case 1:输入:5,输出:0 0 1 2;case 2:输入:12,输出:0 2 2 2;case 3:输入:773535,输出:1 1 267 838

  9. 密码脱落

    X 星球的考古学家发现了一批古代留下来的密码.
    这些密码是由 A、B、C、D 四种植物的种子串成的序列。
    仔细分析发现,这些密码串当初应该是前后对称的 (也就是我们说的镜像串).
    由于年代久远,其中许多种子脱落了,因而可能会失去镜像的特征.
    你的任务是:
    给定一个现在看到的密码串,计算一下从当初的状态,它要至少脱落多少个种子,才可能会变成现在的样子.
    输人一行,表示现在看到的密码串 (长度不大于 1000)要求输出一个正整数,表示至少脱落了多少个种子。

    public class MiMaTuoLuo {
    static int min=0,num=0;
       static String inputstr;
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        inputstr=scanner.next();
        min=inputstr.length();
        fcode(0, min-1, 0);
        System.out.println(min);
    }
    public static  void fcode(int left,int right,int num){
        if (left>=right) {
            min=min

    测试用例:case 1:输入:ABCBA,输出:0;case 2:输入:ABDCDCBABC,输出:3


第八届 省赛(真题课件59)

  1. 购物单

    小明刚刚找到工作,老板人很好,只是老板夫人很爱购物。老板忙的时候经常让小明帮忙到商场代为购物。小明很厌烦,但又不好推辞.
    这不,XX 大促销又来了! 老板夫人开出了长长的购物单,都是有打折优惠的.小明也有个怪癖,不到万不得已,从不刷卡,直接现金搞定。现在小明很心烦,请你帮他计算一下,需要从取款机上取多少现金,才能搞定这次购物
    取款机只能提供 100 元面额的纸币。小明想尽可能少取些现金,够用就行了.
    你的任务是计算出,小明最少需要取多少现金.

    以下是让人头疼的购物单,为了保护隐私,物品名称被隐藏了

    需要说明的是,88 折指的是按标价的 88%计算,而 8 折是按 80%计算,余者类推特别地,半价是按 50%计算.
    请提交小明要从取款机上提取的金额,单位是元.答案是一个整数,类似 4300 的样子,结尾必然是 00,不要填写任何多余的内容

    public class GouWuDan {
       public static void main(String[] args) {
           double ans = 180.90 * 88 + 10.25 * 65 + 56.14 * 90 + 104.65 * 90 + 100.30 * 88 + 297.15 * 50 + 26.75 * 65 + 130.62 * 50 + 240.28 * 58 + 270.62 * 80 + 115.87 * 88 + 247.34 * 95 + 73.21 * 90 + 101.00 * 50 + 79.54 * 50 + 278.44 * 70 + 199.26 * 50 + 12.97 * 90 + 166.30 * 78 + 125.50 * 58 + 84.98 * 90 + 113.35 * 68 + 166.57 * 50 + 42.56 * 90 + 81.90 * 95 + 131.78 * 80 + 255.89 * 78 + 109.17 * 90 + 146.69 * 68 + 139.33 * 65 + 141.16 * 78 + 154.74 * 80 + 59.42 * 80 + 85.44 * 68 + 293.70 * 88 + 261.79 * 65 + 11.30 * 88 + 268.27 * 58 + 128.29 * 88 + 251.03 * 80 + 208.39 * 75 + 128.88 * 75 + 62.06 * 90 + 225.87 * 75 + 12.89 * 75 + 34.28 * 75 + 62.16 * 58 + 129.12 * 50 + 218.37 * 50 + 289.69 * 80; 
        System.out.printf("%.2f",ans/100);
    }
    }

    答案:5200 (运行结果:5136.86)

  2. 纸牌三角形

    A,2,3,4,5,6,7,8,9 共 9 张纸牌排成一个正三角形(A 按 1计算)要求每个边的和相等下图就是一种排法 (如有对齐问题,参看 p1.png).

    这样的排法可能会有很多.
    如果考虑旋转、镜像后相同的算同一种,一共有多少种不同的排法呢?
    请你计算并提交该数字.

    public class ZhiPaiSanJiaoXing {
    static int v[]=new int[10];
    static int arr[]=new int[10];
    static int sum=0;
    public static void main(String[] args) {
        f(1);
        System.out.println(sum/6);
    }
    private static void f(int k) {
        if(k>9) {
            if(check()) {
                sum++;
            }
            return;
        }
        for(int i=1;i<=9;i++) {
            if(v[i]==0) {
                v[i]=1;
                arr[k]=i;
                f(k+1);
                v[i]=0;
            }
        }
    
    }
    private static boolean check() {
        int a=arr[1]+arr[2]+arr[3]+arr[4];
        int b=arr[4]+arr[5]+arr[6]+arr[7];
        int c=arr[7]+arr[8]+arr[9]+arr[1];
        if(a==b&&a==c) {
            return true;
        }else {
            return false;
        }
    }
    }

    答案:144

  3. 承压计算

    X 星球的高科技实验室中整齐地堆放着某批珍贵金属原料
    每块金属原料的外形、尺寸完全一致,但重量不同.金属材料被严格地堆放成金字塔形

    其中的数字代表金属块的重量 (计量单位较大)。
    最下一层的 X 代表 30 台极高精度的电子秤。
    假设每块原料的重量都十分精确地平均落在下方的两个金属块上,最后,所有的金属块的重量都严格精确地平分落在最底层的电子秤上.电子秤的计量单位很小,所以显示的数字很大.
    工作人员发现,其中读数最小的电子秤的示数为: 2086458231
    请你推算出: 读数最大的电子的示数为多少?

    public class ChengYaJiSuan {
    public static void main(String[] args) {
        Scanner s=new Scanner(System.in);
        double arr[][]=new double[30][30];
        for(int i=0;i<29;i++){
            for(int j=0;j<=i;j++){
                arr[i][j]=s.nextInt();
            }
        }
        for(int i=1;i<30;i++){
            for(int j=0;j<=i;j++){
                if(j==0)
                    arr[i][j]+=arr[i-1][j]*1.0/2;
                else arr[i][j]+=arr[i-1][j]*1.0/2+arr[i-1][j-1]*1.0/2;;
            }
        }
        Arrays.sort(arr[29]);
        System.out.println(2086458231/arr[29][0]*arr[29][29]);
    }
    }

    答案:72665192664 (运行结果:7.2665192664E10)

    备注:运行时需要把题目的金字塔数字部分输入

  4. 魔方状态

    二阶魔方就是只有 2 层的魔方,只由 8 个小块组成如图 pl.png 所示
    小明很淘气,他只喜欢 3 种颜色,所有把家里的二阶魔方重新涂了颜色,如下:

    前面:橙色 右面:绿色 上面:黄色 左面:绿色 下面: 橙色 后面:黄色
    请你计算一下,这样的魔方被打乱后,一共有多少种不同的状态
    如果两个状态经过魔方的整体旋转后,各个面的颜色都一致,则认为是同一状态.

    public class MoFangZhuangTai {
    static int count;
    static List list=new ArrayList<>();
    public static void main(String[] args)
    {
        String string="11112233";
        f(string.toCharArray(),0);
        System.out.println(count);
    }
    
    private static void f(char[] charArray, int i)
    {
        if (i==8)
        {
            String string=new String(charArray);
            String string2=reverse(string);
            if (list.contains(string)||list.contains(string2))
            {
                return;
            }
            count++;
            System.out.println(string);
            list.add(string);
        }
    
        for (int j = i; j < charArray.length; j++)
        {
            char old=charArray[i];
            charArray[i]=charArray[j];
            charArray[j]=old;
    
            f(charArray, i+1);
    
            old=charArray[i];
            charArray[i]=charArray[j];
            charArray[j]=old;
        }
    }
    
    private static String reverse(String string)
    {
        String string2="";
        for (int i = 0; i < string.length(); i++)
        {
            string2=string.charAt(i)+string2;
        }
        return string2;
    }
    }

    答案:216

  5. 取数位

    求 1 个整数的第 k 位数字有很多种方法

    以下的方法就是一种。

    对于题目中的测试数据,应该打印 5.

    public class Main {
    static int len(int x){
           if(x<10) return 1;
           return len(x/10)+1;
       }
    
       // 取x的第k位数字
       static int f(int x, int k){
           if(len(x)-k==0) return x%10;
           return f(x/10,k);  //填空
       }
    
       public static void main(String[] args)
       {
           int x = 23513;
           //System.out.println(len(x));
           System.out.println(f(x,3));
       }
    }

    答案:f(x/10,k)

  6. 最大公共子串

    最大公共子串长度问题就是:
    求两个串的所有子串中能够匹配上的最大长度是多少
    比如:"abcdkkk”和"baabedadabc"可以找到的最长的公共子串是"abcd",所以最大公共子串长度为 4.
    下面的程序是采用矩阵法进行求解的,这对串的规模不大的情况还是比较有效的解法.
    请分析该解法的思路,并补全划线部分缺失的代码

    public class ZuiDaGongGongZiChuan {
    static int f(String s1, String s2)
    {
        char[] c1 = s1.toCharArray();//abcdkkk
        char[] c2 = s2.toCharArray();//baabcdadabc
        //二维数组a要多出1列,因为下面的循环,如果两个数相等,则把数加到后一个
        int[][] a = new int[c1.length+1][c2.length+1];
    
        int max = 0;
        for(int i=1; i max) //从这里a[i][j]的判断,可以推出上一行的代码
                        max = a[i][j];
                }
            }
        }
    
        return max;
    }
    
    public static void main(String[] args){
        int n = f("abcdkkk", "baabcdadabc");
        System.out.println(n);
    }
    }

    答案:a[i-1][j-1]+1

  7. 日期问题

    小明正在整理一批历史文献,这些历史文献中出现了很多日期。小明知道这些日期都在 1960年 1 月 1 日至 2059 年 12 月 31 日。令小明头疼的是,这些日期采用的格式非常不统一,有采用年/月/日的,有采用月/日/年的,还有采用日/月/年的。更加麻烦的是,年份也都省略了前两位,使得文献上的一个日期,存在很多可能的日期与其对应.
    比如 02/03/04,可能是 2002 年 03 月 04 日、2004 年 02 月 03 日或 2004 年 03 月 02 日
    给出一个文献上的日期,你能帮助小明判断有哪些可能的日期对其对应吗?

    public class RiQiWenTi {
       static int[] m = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
       static List list = new ArrayList<>();    // list
       static TreeSet set = new TreeSet<>();    // set 会去重,并自动排好序
    
       // 判断闰年
       static int judge(int year) {
           if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) return 1;
           return 0;
       }
    
       // 获取每个月的天数
       static int getDays(int year, int month) {
           if (month == 2) return 28 + judge(year);
           return m[month];
       }
    
       static void func(int year, int month, int day) {
           if (year <= 59)
               year = year + 2000;
           else
               year = year + 1900;
           if (month <= 12 && month >= 1 && getDays(year, month) >= day && day > 0) {
               if (month < 10 && day < 10)
                   set.add(Integer.parseInt("" + year + "0" + month + "0" + day));
               else if (month < 10)
                   set.add(Integer.parseInt("" + year + "0" + month + day));
               else if (day < 10)
                   set.add(Integer.parseInt("" + year + month + "0" + day));
               else
                   set.add(Integer.parseInt("" + year + month + day));
           }
       }
       public static void main(String[] args) {
           Scanner scanner = new Scanner(System.in);
           String str;
           str = scanner.next();
           int a, b, c;
           String[] s = str.split("/");
           a = Integer.parseInt(s[0]);
           b = Integer.parseInt(s[1]);
           c = Integer.parseInt(s[2]);
           // AA/BB/CC  CC/AA/BB  CC/BB/AA
           func(a, b, c);
           func(c, a, b);
           func(c, b, a);
           list.addAll(set);
           for (int i = 0; i < list.size(); i++) {
               String result = "" + list.get(i);
               System.out.println(result.substring(0, 4) + "-" + result.substring(4, 6) + "-" + result.substring(6, 8));
           }
       }
    }

    测试用例:输入:02/03/04,输出:2002-03-04\n2004-02-03\n2004-03-02

  8. 包子凑数

    小明几乎每天早晨都会在一家包子铺吃早餐。他发现这家包子铺有 N 种蒸笼,其中第i种蒸笼恰好能放 Ai 个包子。每种慕笼都有非常多笼,可以认为是无限笼.
    每当有顾客想买 X 个包子,实包子的大叔就会迅速选出若干笼包子来,使得这若干笼中恰好一共有X个包子,比如一共有3 种蒸笼,分别能放3、4和5 个包子当顾客想买 11 个包子时,大叔就会选 2 笼 3 个的再加1 笼 个的(也可能选出 1笼 3 个的再加2 笼4 个的)
    当然有时包子大叔无论如何也凑不出顾客想买的数量。比如一共有 3 种蒸笼,分别能放 4.
    5 和 6 个包子。而顾客想买 7个包子时,大叔就凑不出来了.
    小明想知道一共有多少种数目是包子大叔凑不出来的。

    public class BaoZiCouShu {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int a[] = new int[101];
    
        for (int i = 1; i <= n; i++)
            a[i] = sc.nextInt();
        int yueshu = a[1];
        for (int i = 2; i <= n; i++) {
            yueshu = yue(yueshu, a[i]);
        }
        if (yueshu != 1) {
            System.out.println("INF");
        } else {
            boolean dp[] = new boolean[10010];
            dp[0] = true;
            for (int i = 1; i <= n; i++) {
                for (int j = 0; j + a[i] <= 10000; j++) {
                    if (dp[j]) {
                        dp[j + a[i]] = true;
                    }
                }
            }
            int sum = 0;
            for (int i = 0; i <= 10000; i++)
                if (dp[i] == false)
                    sum++;
            System.out.println(sum);
        }
    }
    
    private static int yue(int x, int y) {
        if (y == 0)
            return x;
        else
            return yue(y, x % y);
    }
    }

    测试用例:case 1:输入:2 4 5,输出:6;case 2:输入:2 4 6,输出:INF

  9. 分巧克力

    儿童节那天有 K 位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友们.小明一共有 N 块巧克力,其中第 i块是 Hix Wi 的方格组成的长方形
    为了公平起见,小明需要从这 N 块巧克力中切出 K 块巧克力分给小朋友们。切出的巧克力需要满足:
    1.形状是正方形,边长是整数
    2.大小相同
    例如一块 6x5 的巧克力可以切出 6 块 2x2 的巧克力或者 2 块 3x3 的巧克力
    当然小朋友们都希望得到的巧克力尽可能大,你能帮小 Hi 计算出最大的边长是多少么?

    public class FenQiaoKeLi {
    static int n , k;//n块巧克力,k个小朋友
       static int[] w=new int[100001];//记录每块巧克力的宽,以最大数据开辟空间
       static int[] h=new int[100001];//记录每一块巧克力的高,以最大数据开辟空间
       static int N = 100001;//最大数据
       //判断和是否满足k个小朋友分
       public static int getsum(int u){//参数u就是所选的边长
           int sum = 0;
           for(int i = 0 ; i=k){//判断以此中位数为边长进行切割时,每块巧克力的切割个数是否能够k个小朋友分
                   left=mid;//若能够k个小朋友分,将左端点等于中间值进行下一次更新(mid = (left + right + 1)/2)中间值,直到找到边长最大的临界值
               }else{
                   right = mid-1;//若不能够k个小朋友分,则所选边长过大,右端点要向左移,直到找到满足的最大边长
               }
    
           }
           System.out.println(left);
       }
    }

    测试用例:输入:2 10 6 5 5 6,输出:2

  10. k倍区间

    给定一个长度为 N 的数列,A1,A2,... AN,如果其中一段连续的子序列 Ai, Ai+,.. Aj<=j)之和是 K 的倍数,我们就称这个区间[i,]是 K 倍区间
    你能求出数列中总共有多少个 K 倍区间吗?

    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt(), k = sc.nextInt();
    long ans = 0;
    int[] sum = new int[n + 1];
    int[] count = new int[100000];
    for (int i = 1; i <= n; i++)
        sum[i] = (sum[i - 1] + sc.nextInt()) % k;
    count[0] = 1;
    for (int i = 1; i <= n; i++)
        ans += count[sum[i]]++;
    System.out.println(ans);
    }

    测试用例:输入:5 2 1 2 3 4 5,输出:6


第九届 省赛(真题课件79)

  1. 哪天返回

    小明被不明势力劫持.后被扔到x星站再无问津.小明得知每天都有飞船飞往地球,但需要108元的船票,而他却身无分文.
    他决定在x星战打工.好心的老板答应包食宿,第1天给他Ⅰ元钱.并且,以后的每一天都比前一天多2元钱,直到他有足够的钱买票.请计算一下,小明在第几天就能凑够108元,返回地球.

    public class NaTianFanHui {
    public static void main(String[] args) {
           int i = 1, num = 1, sum = 1;
           while (sum < 108) {
               sum += num += 2;
               i++;
           }
           System.out.print(i);
       }
    }

    答案:11

  2. 猴子分香蕉

    5只猴子是好朋友,在海边的椰子树上睡着了.这期间,有商船把一大堆香蕉忘记在沙滩上离去.
    第1只猴子醒来,把香蕉均分成5堆,还剩下1个,就吃掉并把自己的一份藏起来继续睡觉.第⒉只猴子醒来,重新把香蕉均分成5堆,还剩下2个,就吃掉并把自己的一份藏起来继续睡觉.
    第3只猴子醒来,重新把香蕉均分成5堆,还剩下3个,就吃掉并把自己的一份藏起来继续睡觉.
    第4只猴子醒来,重新把香蕉均分成5堆,还剩下4个,就吃掉并把自己的一份藏起来继续睡觉.
    第5只猴子醒来,重新把香蕉均分成5堆,哈哈,正好不剩!
    请计算一开始最少有多少个香蕉.

    public class HouZiFenXiangJiao {
    public static void main(String[] args) {
           int i, n;
           for (i = n = 1; true; n = ++i) {
               if (n % 5 != 1) continue;
               n = n / 5 * 4;
               if (n % 5 != 2) continue;
               n = n / 5 * 4;
               if (n % 5 != 3) continue;
               n = n / 5 * 4;
               if (n % 5 != 4) continue;
               n = n / 5 * 4;
               if (n > 0 && n % 5 == 0) break;
           }
           System.out.print(i);
       }
    }

    答案:3141

  3. 字母阵列

    仔细寻找,会发现:在下面的8x8的方阵中,隐藏着字母序列: "LANQIAO".

    我们约定:序列可以水平,垂直,或者是斜向;并且走向不限(实际上就是有一共8种方向).上图中一共有4个满足要求的串.
    下面有一个更大的(100x100)的字母方阵.你能算出其中隐藏了多少个“LANQIAO”吗?

    public class ZiMuZhenLie {
    public static void main(String[] args) {
    
           //定义一个100×100的字母矩阵
           char[][] data=new char[100][100];
           //定义一个方向数组,8个方向
           int [][]next=new int[][]{{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1}};
           Scanner sc=new Scanner(System.in);
           for (int i = 0; i <100 ; i++) {
               data[i]=sc.next().toCharArray();
           }
           sc.close();
    
           char[] fn=new char[]{'L','A','N','Q','I','A','O'};
           for (int i = 0; i <100 ; i++) {
               for (int j = 0; j <100 ; j++) {
                   if (data[i][j]=='L')
                   {
                        dfs(1,i,j,data,next,fn);
                   }
               }
           }
           System.out.println(count);
    
       }
       static  int count=0;
       //分别对8个方向进行寻找满足条件的字串
       public static  void dfs(int step,int i,int j,char [][]data,int [][]next,char[] fn)
       {
    
           int tx;
           int ty;
           tx=i;
           ty=j;
            //顺时针方向
           //首先向上,再向右上.....
           for (int k = 0; k <8 ; k++) {
               while(step!=7)
               {
                   tx=tx+next[k][0];
                   ty=ty+next[k][1];
                   if (tx<0||ty<0||tx>=data.length||ty>= data[0].length)
                   {
                       break;
                   }
                   if (data[tx][ty]==fn[step])
                   {
                       step++;
                   }
                   else{
                       break;
                   }
                   if (step==7)
                   {
                       count++;
                   }
               }
               //这里注意每个方向尝试后要初始化原点位置以及步数
               tx=i;
               ty=j;
               step=1;
           }
       }
    }

    答案:41

    备注:运行时把图中字母阵列输入

  4. 第几个幸运数

    到x星球旅行的游客都被发给一个整数,作为游客编号.x星的国王有个怪癖,他只喜欢数字3,5和7.
    国王规定,游客的编号如果只含有因子:3,5,7,就可以获得一份奖品.
    我们来看前10个幸运数字是:
    3 5 79 15 21 25 27 3545
    因而第11个幸运数字是:49
    小明领到了一个幸运数字59084709587505,他去领奖的时候,人家要求他准确地说出这是第几个幸运数字,否则领不到奖品.
    请你帮小明计算一下,59084709587505是第几个幸运数字.

    public class DiJiGeXingYunShu {
    public static void main(String[] args) {
           long n = 59084709587505L, cnt = 0;
           for (long a = 1; a <= n; a *= 3)
               for (long b = 1; b <= n; b *= 5)
                   for (long c = 1; c <= n; c *= 7)
                       if (a * b * c <= n && a * b * c > 0) cnt++;
           System.out.print(cnt - 1);
       }
    }

    答案:1905

  5. 书号验证

    2004年起,国际ISBN中心出版了《13位国际标准书号指南》.原有10位书号前加978作为商品分类标识;校验规则也改变.校验位的加权算法与10位.ISBN的算法不同,具体算法是:
    用1分别乘ISBN的前12位中的奇数位(从左边开始数起),用3乘以偶数位,乘积之和以10为模,10与模值的差值再对10取模(即取个位的数字)即可得到校验位的值,其值范围应该为0~9.

    public class ShuHaoYanZheng {
    static boolean f(String s){
           int k=1;
           int sum = 0;
           for(int i=0; i12) break; 
           }
    
           return s.charAt(s.length()-1)-'0' == (10-sum % 10)%10;
       }
    
       public static void main(String[] args){
           System.out.println(f("978-7-301-04815-3"));
           System.out.println(f("978-7-115-38821-6"));
       }
    }

    答案:(c - '0') * (1 == (k & 1)? 1: 3)

  6. 打印大X

    如下的程序目的是在控制台打印输出大X.可以控制两个参数:图形的高度,以及笔宽.
    用程序中的测试数据输出效果:
    (如果显示有问题,可以参看p1.png)

    static void f(int h, int w){
           System.out.println(String.format("高度=%d, 笔宽=%d",h,w));
           int a1 = 0;
           int a2 = h - 1;
    
           for(int k=0; k

    答案:while (p++ < q) System.out.print("*")

    备注:和第六届第九题一样

  7. 缩位求和

    在电子计算机普及以前,人们经常用一个粗略的方法来验算四则运算是否正确.比如:248* 15= 3720
    把乘数和被乘数分别逐位求和,如果是多位数再逐位求和,直到是1位数,得

    2+4+8= 14 ==> 1+4= 5;
    1+5=6
    5 6
    而结果逐位求和为3
    5
    6 的结果逐位求和与3符合,说明正确的可能性很大!!(不能排除错误)
    请你写一个计算机程序,对给定的字符串逐位求和:
    输入为一个由数字组成的串,表示n位数(n<1000);输出为一位数,表示反复逐位求和的结果.

    public class SuoWeiQiuHe {
    public static void main(String[] args) throws IOException {
           byte[] buff = new byte[1024];
           int len = System.in.read(buff);
           int[] a = new int[len];
           for (int i = 0; i < len; i++)
               a[i] = byteToValue(buff[i]);
           while (len > 1) {
               for (int i = 1; i < len; i++) a[0] += a[i];
               for (int i = 0, pre = a[0]; pre != 0; len = ++i) {
                   a[i] = pre % 10;
                   pre /= 10;
               }
           }
           System.out.print(a[0]);
       }
    
       static int byteToValue(byte n) { return n > '0' && n < '9'? n & 0xf: 0;
       }
    }

    测试用例:case 1:Input:35379,Output:9;case 2:Input:7583676109608471656473500295825,Output:1

  8. 等腰三角形

    本题目要求你在控制台输出一个由数字组成的等腰三角形.具体的步骤是:
    1.先用1,2,3,...的自然数拼一个足够长的串
    2.用这个串填充三角形的三条边.从上方顶点开始,逆时针填充.比如,当三角形高度是8时:

    输入,一个正整数n(3<n<300),表示三角形的高度输出,用数字填充的等腰三角形.
    为了便于测评,我们要求空格一律用"."代替.

    public class DengYaoSanJiaoXing {
    public static void main(String[] args) {
           Scanner sc=new Scanner(System.in);
           int n=sc.nextInt();
           //计算等腰三角形总共需要多少数字
           int sum=4*n-4;
           //int sum = 1 + (n - 1) * 2 + (2 * n - 3);
           String str="";
           for (int i = 1; str.length() < sum; i++) {
               str=str+String.valueOf(i);
           }
           char[] ch = str.substring(0, sum).toCharArray();
    
           //打印第一行
           for (int i = 0; i < n-1; i++) {
               System.out.print(".");
           }
           System.out.println(1);
    
           //打印2到n-1行
           for (int i = 1; i < n-1; i++) {
    
               for (int j = 0; j < n-i-1; j++) {
                   System.out.print(".");
               }
    
               System.out.print(ch[i]);
    
               for (int j = 0; j < i*2-1; j++) {
                   System.out.print(".");
               }
               System.out.println(ch[sum-i]);
    
           }
    
           //打印最后一行4*n-4-(n-2)=3*n-2
           for (int i = n-1; i < 3*n-2; i++) {
               System.out.print(ch[i]);
           }
    
       }
    }

    测试用例:见真题文档:https://www.lanqiao.cn/courses/2786/learning/?id=67812&compatibility=false (需要登录)

  9. 小朋友崇拜圈

    班里N个小朋友,每个人都有自己最崇拜的一个小朋友(也可以是自己).在一个游戏中,需要小朋友坐一个圈,
    每个小朋友都有自己最崇拜的小朋友在他的右手边.求满足条件的圈最大多少人?
    小朋友编号为1,2,3,..N
    输入第一行,一个整数N(3<N<100000)接下来一行N个整数,由空格分开.

    要求输出一个整数,表示满足条件的最大圈的人数.

    解释:
    如图p1.png所示,崇拜关系用箭头表示,红色表示不在圈中.显然,最大圈是[2453]构成的圈

    public class XiaoPengYouChongBaiQuan {
    static int n,now,next,max,len;//个数,当前起点,当前下一个点,最长步数,记录长度
    static int flag[];//记录是否被遍历过一遍
    static int p[];
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        p = new int[n+1];
        flag = new int[n+1];
        for(int i = 1;i<=n;i++){
            p[i] = sc.nextInt();
        }
        for(int i =1;i<=n;i++){
            now = i;//当前起点是i
            len = 0;//步数为0
            dfs(p[i]);//传入当前起点的下一个指向
        }
        System.out.println(max +1);//因为是先判断后len++,所以少加一个1
    }
    private static void dfs(int num) {
        len ++;//没找一次步数加一
           next = p[num];//下一个的指向
        if(now == next){//如果下一个指向与初始值相等,说明是个圈
            max = Math.max(max,len);//记录最大步数
            return;
        }
        //当前的下一个指向
        if(pd(next)){//判断下一个是否下标越界,是否已经被遍历过
            flag[next] = 1;
            dfs(next);
        }else{
            len = 0;
            Arrays.fill(flag,0);//恢复
            return;
        }
    }
    private static boolean pd(int i) {
        if(i<0 || i>=n){
            return false;
        }
        if(flag[i] == 1){//已经被遍历过且不满足check说明陷入了死循环,返回false
            return false;
        }
        return true;
    }
    }

    测试用例:case 1:I:9\n3 4 2 5 3 8 4 6 9,O:4;case 2:I:30\n22 28 16 6 27 21 30 1 29 10 9 14 24 11 7 2 8 5 26 4 12 3 25 18 20 19 23 17 13 15,O:16

  10. 耐摔指数

    x星球的居民脾气不太好,但好在他们生气的时候唯一的异常举动是:摔手机.
    各大厂商也就纷纷推出各种耐摔型手机.x星球的质监局规定了手机必须经过耐摔测试,并且评定出一个耐摔指数来,之后才允许上市流通.
    x星球有很多高耸入云的高塔,刚好可以用来做耐摔测试.塔的每一层高度都是一样的,与地球上稍有不同的是,他们的第一层不是地面,而是相当于我们的2楼.
    如果手机从第7层扔下去没摔坏,但第8层摔坏了,则手机耐摔指数=7.特别地,如果手机从第1层扔下去就坏了,则耐摔指数=0.
    如果到了塔的最高层第n层扔没摔坏,则耐摔指数=n
    为了减少测试次数,从每个厂家抽样3部手机参加测试.
    如果已知了测试塔的高度,并且采用最佳策略,在最坏的运气下最多需要测试多少次才能确定手机的耐摔指数呢?
    输入数据,一个整数n (3<n<10000),表示测试塔的高度.输出一个整数,表示最多测试多少次.

    public class NaiShuaiZhiShu {
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            int n = sc.nextInt();
            int[] x = new int[1000];
            int sum = 1;
            for (int i = 0; sum < n; i++) {
                sum = i + sum;
                x[i] = sum;
            }
            sum = 1;
            int k = 0;
            for (int i = 0; sum < n; i++) {
                sum = x[i] + sum;
                k++;
            }
            System.out.println(k);
        }
    }

    测试用例:case 1:I:3,O:2;case 2:I:7,O:3


第十届 省赛(真题课件86)

  1. 求和

    小明对数位中含有2、0、1、9的数字很感兴趣,在1到40中这样的数包括1、2、9、10至32、39和 40,共28个,他们的和是574。
    请问,在1到2019中,所有这样的数的和是多少?

    public class QiuHe {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        long sum = 0;
        for (int i = 1; i <= n; i++) {
            String temp = i + "";
            if (temp.contains("2") || temp.contains("0") || temp.contains("1") || temp.contains("9"))
                sum += i;
        }
        System.out.println(sum);
    }
    }

    答案:1905111

    备注:运行时输入2019

  2. 矩形切割

    小明有一些矩形的材料,他要从这些矩形材料中切割出一些正方形。当他面对一块矩形材料时,他总是从中间切割一刀,切出一块最大的正方形,剩下一块矩形,然后再切割剩下的矩形材料,直到全部切为正方形为止。
    例如,对于一块两边分别为5和3的材料(记为5×3),小明会依次切出3×3、2×2、1×1、1×1共4个正方形。
    现在小明有一块矩形的材料,两边长分别是2019和 324。请问小明最终会切出多少个正方形?

    public class JvXingQieGe {
    public static void main(String[] args) {
           int leng=2019;
           int wide=324;
           int ans=0; //答案
           while(leng>=1&&wide>=1){
            //找其中的最小值作为正方形的边长
               if(leng>wide){
                   leng-=wide;
               }
               else{
                   wide-=leng;
               }
               ans++;
           }
           System.out.println(ans);
       }
    }

    答案:21

  3. 不同子串

    一个字符串的非空子串是指字符串中长度至少为1的连续的一段字符组成的串。例如,字符串aaab有非空子串a,b, aa,ab,aaa,aab,aaab,一共7个。注意在计算时,只算本质不同的串的个数。
    请问,字符串0100110001010001有多少个不同的非空子串?

    public class BuTongZiChuan {
    public static void main(String[] args) {
        String arr = "0100110001010001";
        Set set = new HashSet();
        for (int i = 0; i < arr.length(); i++) {
            // 以i为开头的所有可能结果所以j必须大于i
            for (int j = i + 1; j <= arr.length(); j++) {
                // 虽然substring 下标i~j的时候是不包含j的
                // 每个数字开头本身也是个非空子串,也符合题意
                // 所以不需要变成substring(i,j+1)
                // 由于需要包含到最后一个字符所以j最大值为arr,length();
                String temp = arr.substring(i, j);
                set.add(temp);
            }
        }
        System.out.println(set.size());
    }
    }

    答案:100

  4. 质数

    我们知道第一个质数是2、第二个质数是3、第三个质数是5……请你计算第2019个质数是多少?

    public class ZhiShu {
    public static void main(String[] args) {
           int ans=0;
           int res=0;//下面res++,就直接从1开始了改
           while (ans<=2019){
               res++;
               if(check(res)){
                   ans++;
               }
           }
           System.out.println(res);
       }
       public static boolean check(int nums){
           int flag=0;
           for(int i=2;i

    答案:17569

  5. 最大降雨量

    由于沙之国长年干旱,法师小明准备施展自己的一个神秘法术来求雨。这个法术需要用到他手中的49张法术符,上面分别写着1至49这49个数字。法术一共持续7周,每天小明都要使用一张法术符,法术符不能重复使用。
    每周,小明施展法术产生的能量为这周7张法术符上数字的中位数。法术施展完7周后,求雨将获得成功,降雨量为7周能量的中位数。
    由于干旱太久,小明希望这次求雨的降雨量尽可能大,请大最大值是多少?

    解答:49 - 15 = 34;纯数学解算,可以百度,推荐两篇文章:1. 第十届蓝桥杯省赛 A组 C最大降雨量(思维)_蓝桥杯 最大降雨-CSDN博客 2. java蓝桥杯B组最大降雨量_java实现最大降雨量-CSDN博客

    答案:34

  6. 旋转

    图片旋转是对图片最简单的处理方式之一,在本题中,你需要对图片顺时针旋转90度。
    我们用一个nxm的二维数组来表示一个图片,例如下面给出一个3×4 的图片的例子:

    这个图片顺时针旋转90度后的图片如下:

    给定初始图片,请计算旋转后的图片。

    public class XuanZhuan {
    public static void main(String[] args) {
           Scanner input=new Scanner(System.in);
           int n=input.nextInt();
           int m=input.nextInt();
           int resx=0;
           int resy=0;
           //最后输出数组的行和列
           resx=m;
           resy=n;
           System.out.println(resx+" "+resy);
           int [][]arr=new int[n+1][m+1];
    
           int [][]temparr=new int[resx+1][resy+1];
           for(int i=1;i<=n;i++){
               for(int j=1;j<=m;j++){
                   arr[i][j]=input.nextInt();
               }
           }
           for(int i=1;i<=n;i++){
               for(int j=1;j<=m;j++){
                   temparr[j][resy-i+1]=arr[i][j];
               }
           }
           for(int i=1;i<=resx;i++){
               for(int j=1;j<=resy;j++){
                   System.out.print(temparr[i][j]+" ");
               }
               System.out.println();
           }
    
       }
    }

    备注:运行时先输入行数和列数,再输入矩阵

  7. 外卖店优先级

    “饱了么”外卖系统中维护着N家外卖店,编号1~~N。每家外卖店都有一个优先级,初始时(0时刻)优先级都为0。
    每经过1个时间单位,如果外卖店没有订单,则优先级会减少1,最低减到0;而如果外卖店有订单,则优先级不减反加,每有一单优先级加2。
    如果某家外卖店某时刻优先级大于5,则会被系统加入优先缓存中;如果优先级小于等于3,则会被清除出优先缓存。
    给定T时刻以内的M条订单信息,请你计算T时刻时有多少外卖店在优先缓存中。

    public class WaiMaiDianYouXianJi {
    static class My implements Comparable {
           int t, id;
           My(int t, int id) {
               this.t = t;
               this.id = id;
           }
           @Override
           public int compareTo(My m) {
               if (t == m.t) {
                   if (id > m.id) {
                       return 1;
                   } else if (id < m.id) {
                       return -1;
                   }
                   return 0;
               }
               return t > m.t ? 1 : -1;
           }
       }
       private static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
       private static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
    
       private static final int N = 100010;
       private static int[] scores = new int[N]; //第i个店优先级
       private static int[] last = new int[N]; // 第i个店上一个有订单的时刻t = last[id]
       private static boolean[] st = new boolean[N];  //是否在优先队列
       private static My[] orders = new My[N]; //结构体数组
    
       public static void main(String[] args) throws IOException {
           //输入数据
           String[] ss = br.readLine().split(" ");
           int n = Integer.parseInt(ss[0]);
           int m = Integer.parseInt(ss[1]);
           int T = Integer.parseInt(ss[2]);
           for (int i = 0; i < m; i++) {
               ss = br.readLine().split(" ");
               int t = Integer.parseInt(ss[0]);
               int id = Integer.parseInt(ss[1]);
               orders[i] = new My(t, id);
           }
           // 排序
           Arrays.sort(orders, 0, m);
           //循环遍历
           for (int i = 0; i < m;) {
               int j = i;
               while (j < m && orders[i].t == orders[j].t && orders[i].id == orders[j].id) 
                   j++;               
               //循环是为了找到相同的订单,cnt表示相同的数量
               int id = orders[i].id, t = orders[i].t, cnt = j - i;
               i = j;
    
               scores[id] -= t - last[id] - 1; //中间没有订单的数量
               if (scores[id] < 0) scores[id] = 0;
               if (scores[id] <= 3) st[id] = false;
               //上面是处理t时刻之前的减, 下面处理t时刻的加
               scores[id] += cnt*2;
               if (scores[id] > 5) st[id] = true;
    
               last[id] = t;
    
           }
           //最后一个订单t时刻到结尾T那段距离,需要手动计算
           for(int i = 1; i <= n; i++){
               if(last[i] < T){
                   scores[i] -= T - last[i];
                   if (scores[i] <= 3) st[i] = false;
               }
           }
           //计算最终答案
           int res = 0;
           for (int i = 1; i <= n; i++) {
               if (st[i])
                   res++;
           }
           bw.write(res + "\n");
           bw.close();
           br.close();
       }
    }

    测试用例:见真题文档:https://www.lanqiao.cn/courses/2786/learning/?id=70877&compatibility=false

    备注:比较难,建议放弃跳过

  8. 人物相关性分析

    小明正在分析一本小说中的人物相关性。他想知道在小说中Alice和 Bob有多少次同时出现。
    更准确的说,小明定义Alice 和 Bob“同时出现”的意思是:在小说文本中Alice和 Bob 之间不超过K个字符。
    例如以下文本:
    This is a story about Alice and Bob.Alice wants to send a private message to Bob.
    假设K = 20,则Alice和 Bob同时出现了2次,分别是”Alice and Bob”和”Bob. Alice”。前者Alice和 Bob之间有5个字符,后者有2个字符。
    注意:

    1. Alice和 Bob是大小写敏感的,alice或bob 等并不计算在内。
    2. Alice 和 Bob 应为单独的单词,前后可以有标点符号和空格,但是不能有字母。例如Bobbi 亚不算出现了Bob。
    public class RenWuXiangGuanXingFenXi {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int k = sc.nextInt();
        // 换行问题.参考https://blog.csdn.net/zxfly6/article/details/80514903
        sc.nextLine();
        String str = sc.nextLine();
        // 因为符号为两个字符所以把符号替换为任意两个字符以便于str通过split方法分割为数组
        str = str.replaceAll("\\.", " ab ");
        // 以空格和.把句子分割成数组
        String[] strs = str.split("\\s+");
        // 记录关联次数
        int count = 0;
        // 累加Alice后k字符Bob出现的次数
        for (int i = 0; i < strs.length; i++) {
            // 用于记录间隔字符
            int chars = 0;
            if (strs[i].equals("Alice")) {
                // 检索此字符串后的单词
                for (int j = i + 1; j < strs.length; j++) {
                    if (strs[j].equals("Bob") && chars <= k) {
                        // 记录
                        count++;
                    } else {
                        chars = chars + (j - i) + 1 + strs[j].length();
                    }
                }
            }
        }
        //// 累加Bob后k字符Alice出现的次数
        for (int i = 0; i < strs.length; i++) {
            // 用于记录间隔字符
            int chars = 0;
            if (strs[i].equals("Bob")) {
                for (int j = i + 1; j < strs.length; j++) {
                    if (strs[j].equals("Alice") && chars <= k) {
                        count++;
                    } else {
                        chars = chars + (j - i) + 1 + strs[j].length();
                    }
                }
            }
        }
        System.out.println(count);
    }
    }

    测试用例:I:20\nThis is a story about Alice and Bob.Alice wants to send a private message to Bob. ,O:2

    备注:同上题

  9. 等差数列

    数学老师给小明出了一道等差数列求和的题目。但是粗心的小明忘记了一部分的数列,只记得其中N个整数。
    现在给出这Ⅳ个整数,小明想知道包含这N个整数的最短的等差数列有几项?

    public class DengChaShuLie {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int N = input.nextInt();
        int arr[] = new int[N + 1];
        for (int i = 0; i < N; i++) {
            arr[i] = input.nextInt();
        }
        Arrays.sort(arr);
        int Max = arr[N];
        int Min = arr[1];
        int d = 0;
        int cha[] = new int[N];
        int index = 0;
        // 找每个数与第一位的公差
        for (int i = 2; i <= N; i++) {
            cha[index++] = arr[i] - Min;
        }
        // 找最大公差
        for (int i = 0; i < index; i++) {
            // int temp= gcd(cha[i-1],cha[i]);
            d = gcd(cha[i], d);
        }
        // 公差为0的时候原数组就是最小等差数列
        if (d == 0)
            System.out.println(N);
        else
            System.out.println((Max - Min) / d + 1);
    
    }
    
    public static int gcd(int a, int b) {
        if (b == 0)
            return a;
        else {
            return gcd(b, a % b);
        }
    }
    }

    测试用例:I:5\n2 6 4 10 20 ,O:10

  10. 扫地机器人

    小明公司的办公区有一条长长的走廊,由N个方格区域组成,如下图所示。

    走廊内部署了K台扫地机器人,其中第i台在第A;个方格区域中。
    已知扫地机器人每分钟可以移动到左右相邻的方格中,并将该区域清扫干净。
    请你编写一个程序,计算每台机器人的清扫路线,使得
    1.它们最终都返回出发方格,
    2.每个方格区域都至少被清扫一遍,
    3.从机器人开始行动到最后一台机器人归位花费的时间最少。
    注意多台机器人可以同时清扫同一方块区域,它们不会互相影响。输出最少花费的时间。
    在上图所示的例子中,最少花费时间是6。第一台路线:2-1-2-3-4-3-2,清扫了1、2、3、4号区域。第二台路线5-6-7-6-5,清扫了5、6、7。第三台路线10-9-8-9-10,清扫了8、9和 10。

    public class SaoDiJiQiRen {
        static int N;
        static int K;
        static int[] a = new int[1000000];
        static int[] b = new int[1000000];
    
        public static void main(String[] args) {
            int i, L;
            Scanner sc = new Scanner(System.in);
            N = sc.nextInt();
            K = sc.nextInt();
            for (i = 1; i <= K; i++) {
                a[i] = sc.nextInt();
                b[a[i]] = 1;
            }
            L = fun();
            System.out.println(2 * (L - 1));
    
        }
    
        public static boolean check1(int first_L, int L) { // 第一个区间长度为 first_L,之后区间长度都为 L
            int i, j;
            if (first_L + (K - 1) * L < N) {// 第一个区间再加上,其他的机器人和*这段的长度是不是能够够到总长
                return false;
            }
            i = 1; // 第 i 个区间
            j = 1; // 当前查看的方格位置
            while (j <= N) {
                if (b[j] == 1) { // 第 i 个区间内有机器人
                    j = first_L + (i - 1) * L + 1; // j 指向下一个区间起点
                    i++; // 下一个区间
                } else {
                    j++;// 一直检查下一个方格,如果一直没有直到first_L和j相等后,表明真的没有机器人
                    if (j == first_L + (i - 1) * L + 1 || j == N + 1) { // 第 i 个区间内没有机器人
                        return false; // 因为L是不断变大的,first也一直变大,所以检查一直再往后扩展
                    }
                }
            }
            return true;
        }
    
        public static boolean check(int L) {
            int first_L; // 首区间的长度(取值范围:1~L)
            for (first_L = L; first_L > 0; first_L--) {// 倒叙是因为,用大区间可以减少机器人的移动
                if (check1(first_L, L)) {
                    return true;
                }
            }
            return false;
        }
    
        public static int fun() {
            int i, j, L;
            for (L = N / K; L <= N; L++) {// 平均一下,
                if (check(L)) {
                    return L;
                }
            }
            return L;
        }
    }

    测试用例:I:10 3\n5\n2\n10,O:6

    备注:太难


[第十一届 省赛(7月份场)](2020年 第11届 蓝桥杯 Java C组 省赛真题详解及小结【第1场省赛 2020.7.5】-CSDN博客 "略,没有真题课件直接看这篇文章")


第十一届 省赛(真题课件108)

  1. 约数个数

    对于一个整数,能整除这个整数的数称为这个数的约数。例如: 1,2,3,6都是6的约数。
    请问78120有多少个约数。

    public class YueShuGeShu {
    public static void main(String[] args) {
           int ans = 0;
           for (int i = 1; i <= 78120; i++) {
               if (78120 % i == 0) ans++;
           }
           System.out.println(ans);
       }
    }

    答案:96

  2. 寻找2020

    小蓝有一个数字矩阵,里面只包含数字О和2。小蓝很喜欢2020,他想找到这个数字矩阵中有多少个2020 。
    小蓝只关注三种构成2020的方式:
    。同一行里面连续四个字符从左到右构成2020。

    。同一列里面连续四个字符从上到下构成2020。
    。在一条从左上到右下的斜线上连续四个字符,从左上到右下构成2020。例如,对于下面的矩阵:

    一共有5个2020。其中1个是在同一行里的,1个是在同一列里的,3个是斜线上的。
    小蓝的矩阵比上面的矩阵要大,由于太大了,他只好将这个矩阵放在了一个文件里面,在试题目录下有一个文件2020.txt,里面给出了小蓝的矩阵。
    请帮助小蓝确定在他的矩阵中有多少个2020。

    public class XunZhao2020 {
    static int count = 0;
    static char[][] arr2 = new char[400][400];
    static char[] arr3 = { '2', '0', '2', '0' };
    
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        String[] arr = new String[301];
        for (int i = 0; i < 300; i++) {
            arr[i] = input.next();
        }
        for (int i = 0; i < 300; i++) {
            arr2[i] = arr[i].toCharArray();
        }
        for (int i = 0; i < 300; i++) {
            for (int j = 0; j < 300; j++) {
                if (arr2[i][j] == '2') {
                    dfs(i, j);
                }
            }
        }
        System.out.println(count);
    }
    
    public static void dfs(int x, int y) {
        int flag = 1;// 用来判断是否满足条件
        // 找从左往右
        for (int i = 1; i <= 3; i++) {
            // 越界了就说明这个方向肯定不行
            if (y + i < 0 || y + i >= 300) {
                flag = 0;
                break;
            }
            if (arr2[x][y + i] != arr3[i]) {
                flag = 0;
                break;
            }
        }
        if (flag == 1)
            count++;
        // 每判断一次要更新flag=1,以免对下一次判断造成误解
        flag = 1;
        // 从上到下
        for (int i = 1; i <= 3; i++) {
            if (x + i < 0 || x + i >= 300) {
                flag = 0;
                break;
            }
            if (arr2[x + i][y] != arr3[i]) {
                flag = 0;
                break;
            }
        }
        if (flag == 1)
            count++;
        flag = 1;
        // 左上到右下
    
        for (int i = 1; i <= 3; i++) {
            if ((y + i < 0 || y + i >= 300) || (x + i < 0 && x + i >= 300)) {
                flag = 0;
                break;
            }
            if (arr2[i + x][y + i] != arr3[i]) {
                flag = 0;
                break;
            }
        }
        if (flag == 1)
            count++;
    }
    }

    答案:16520

    备注:运行时输入文件中的数列矩阵(无文件,未实测)

  3. 跑步锻炼

    小蓝每天都锻炼身体。
    正常情况下,小蓝每天跑1千米。如果某天是周一或者月初(1日),为了激励自己,小蓝要跑﹖千米。如果同时是周一或月初,小蓝也是跑⒉千米。
    小蓝跑步已经坚持了很长时间,从2000年1月1日周六(含)到2020年10月1日周四(含)。请问这段时间小蓝总共跑步多少千米?

    static int[] week = { 6, 7, 1, 2, 3, 4, 5 };// 一月一号星期六,依次往后推
    static int[] months = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    
    public static void main(String[] args) {
        int ans = 0;
        int sumday = 0;// 总天数.用来判断星期几
        // 年
        for (int year = 2000; year <= 2020; year++) {
    
            // 判断是否是闰年
            if (!check(year)) {
                // 不是闰年就按正常的来
                for (int month = 1; month <= 12; month++) {
                    for (int day = 1; day <= months[month]; day++) {
                        if (day == 1 || week[sumday % 7] == 1)
                            ans += 2;
                        else
                            ans++;
                        sumday++;
                    }
                }
            }
            // 是闰年
            else {
                if (year == 2020) {// 特判一下2020年因为今年就10个月跑
                    for (int month = 1; month <= 10; month++) {
                        if (month == 10) {
                            ans += 2;
                            break;
                        }
                        if (month != 2 && month < 10) {
                            for (int day = 1; day <= months[month]; day++) {
                                if (day == 1 || week[sumday % 7] == 1)
                                    ans += 2;
                                else
                                    ans++;
                                sumday++;
                            }
                        } else if (month == 2) {
                            for (int day = 1; day <= 29; day++) {
                                if (day == 1 || week[sumday % 7] == 1)
                                    ans += 2;
                                else
                                    ans++;
                                sumday++;
                            }
                        }
                    }
                } else {
                    for (int month = 1; month <= 12; month++) {
                        if (month != 2) {
                            for (int day = 1; day <= months[month]; day++) {
                                if (day == 1 || week[sumday % 7] == 1)
                                    ans += 2;
                                else
                                    ans++;
                                sumday++;
                            }
                        } else {
                            for (int day = 1; day <= 29; day++) {
                                if (day == 1 || week[sumday % 7] == 1)
                                    ans += 2;
                                else
                                    ans++;
                                sumday++;
                            }
                        }
                    }
    
                }
    
            }
    
        }
        System.out.println(ans);
    }
    
    static boolean check(int year) {
        if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
            return true;
        } else
            return false;
    }
    }

    答案:8879

  4. 平面分割

    20个圆和20条直线最多能把平面分成多少个部分?

    public static void main(String[] args) {
        int result = doFunction(20, 20);
        System.out.println(result);
    }
    
    private static int doFunction(int m, int n) {
        return m * (m - 1) + 1 + 2 * m * n + n * (n + 1) / 2;
    }
    }

    答案:1391

    备注:System.out.println(20*20-20+2+2*20*20+20*(20+1)/2-1); 一行就可以解算

  5. 七段码

    上图给出了七段码数码管的一个图示,数码管中一共有7段可以发光的二极管,分别标记为a, b, c, d, e,f, g.
    小蓝要选择一部分二极管(至少要有一个)发光来表达字符。在设计字符的表达时,要求所有发光的二极管是连成一片的。
    例如:b发光,其他二极管不发光可以用来表达一种字符。
    例如: c发光,其他二极管不发光可以用来表达一种字符。这种方案与上一行的方案可以用来表示不同的字符,尽管看上去比较相似。
    例如: a, b, c, d,e发光,f,g不发光可以用来表达一种字符。
    例如: b, f 发光,其他二极管不发光则不能用来表达一种字符,因为发光的二极管没有连成一片。
    请问,小蓝可以用七段码数码管表达多少种不同的字符?

    public class QiDuanMa {
    static int counts=0;
    static Setset=new HashSet<>();
    static Map>map=new HashMap<>();
    public static void main(String[] args) {
        String str="abcdefg";
        //初始化
        ArrayListlist1=new ArrayList<>();
        ArrayListlist2=new ArrayList<>();
        ArrayListlist3=new ArrayList<>();
        ArrayListlist4=new ArrayList<>();
        ArrayListlist5=new ArrayList<>();
        ArrayListlist6=new ArrayList<>();
        ArrayListlist7=new ArrayList<>();
        list1.add("b");list1.add("f");
        list2.add("a");list2.add("g");list2.add("c");
        list3.add("b");list3.add("g");list3.add("d");
        list4.add("c");list4.add("e");
        list5.add("f");list5.add("g");list5.add("d");
        list6.add("a");list6.add("g");list6.add("e");
        list7.add("f");list7.add("e");list7.add("b");list7.add("c");
        map.put("a", list1);
        map.put("b", list2);
        map.put("c", list3);
        map.put("d", list4);
        map.put("e", list5);
        map.put("f", list6);
        map.put("g", list7);
    
        //求字符串的所有字串
        find("",str,0);
    
        System.out.println(counts);
    }
    static void find(String temp,String str,int index) {
        if(index==str.length()) {
            //最后对得到的字串检查是否是一个连通区域
            if(bfsCheck(temp.toCharArray()))counts++;
            return;
        }
        find(temp,str,index+1);
        find(temp+=str.charAt(index),str,index+1);
    }
    static boolean bfsCheck(char[] strs) {
        //先对简单情形直接判断
        if(strs.length==0)return false;
        if(strs.length==1)return true;
        if(strs.length==2) {
            if(map.get(strs[0]+"").contains(strs[1]+""))return true;
            else return false;
        }
        LinkedList queue=new LinkedList<>();
        int connect=1;
        queue.add(strs[0]+"");
        strs[0]='0';
        while(!queue.isEmpty()) {
            String str  = queue.poll();
            ArrayList list = map.get(str);
            for(int i=0;i

    答案:80

  6. 成绩统计

    小蓝给学生们组织了一场考试,卷面总分为100分,每个学生的得分都是一个0到100的整数。
    如果得分至少是60 分,则称为及格。如果得分至少为85分,则称为优秀。请计算及格率和优秀率,用百分数表示,百分号前的部分四舍五入保留整数。

    public class ChengJiTongJi {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int N = input.nextInt();
        double[] arr = new double[N + 1];
        double hege = 0;
        double better = 0;
        for (int i = 0; i < N; i++) {
            arr[i] = input.nextDouble();
            if (arr[i] >= 60)
                hege++;
            if (arr[i] >= 85)
                better++;
        }
        System.out.println(Math.round((hege / N) * 100) + "%");
        System.out.println(Math.round((better / N) * 100) + "%");
    }
    }

    测试用例:I:7\n80\n92\n56\n74\n88\n100\n0 ,O:71%\n43%

  7. 单词分析

    小蓝正在学习一门神奇的语言,这门语言中的单词都是由小写英文字母组成,有些单词很长,远远超过正常英文单词的长度。小蓝学了很长时间也记不住一些单词,他准备不再完全记忆这些单词,而是根据单词中哪个字母出现得最多来分辨单词。
    现在,请你帮助小蓝,给了一个单词后,帮助他找到出现最多的字母和这个字母出现的次数。

    public class DanCiFenXi {
    public static void main(String[] args) {
           Scanner input=new Scanner(System.in);
           String a=input.next();
           char []arr=a.toCharArray();
           int max=-1;
           int  maxchar=' ';
           int []count=new int[129];
           for(int i=0;imax){
                   max=count[i];
                   maxchar=i;
               }
           }
           System.out.println((char)(maxchar));
           System.out.println(max);
       }
    }

    测试用例:case 1:I:lanqiao ,O:a\n2 ;case 2:longlonglongistoolong ,O:o\n6

  8. 数字三角形

    上图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和。
    路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右边的那个数。此外,向左下走的次数与向右下走的次数相差不能超过1。

    public class ShuZiSanJiaoXing {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        int[][] arr = new int[n + 1][n + 1];
        int[][] dp = new int[n + 1][n + 1];
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= i; j++) {
                arr[i][j] = input.nextInt();
            }
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= i; j++) {
                // 最里面一列只能从上面下来
                if (j == 1) {
                    dp[i][j] = dp[i - 1][j] + arr[i][j];
                }
                // 每行最边上一列只能从左上角下来
                else if (i == j) {
                    dp[i][j] = dp[i - 1][j - 1] + arr[i][j];
                } else {
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - 1]) + arr[i][j];
                }
            }
        }
        if (n % 2 != 0) {
            System.out.println(dp[n][n / 2 + 1]);
        } else {
            System.out.println(Math.max(dp[n][n / 2 + 1], dp[n][n / 2]));
        }
    }
    }

    测试用例:I:5\n7\n3 8\n8 1 0\n2 7 4 4\n4 5 2 6 5 ,O:27

  9. 作物杂交

    作物杂交是作物栽培中重要的一步。已知有N种作物(编号1至N ),第i种作物从播种到成熟的时间为T。作物之间两两可以进行杂交,杂交时间取两种中时间较长的一方。如作物A种植时间为5天,作物B种植时间为7天,则AB杂交花费的时间为7天。作物杂交会产生固定的作物,新产生的作物仍然属于N种作物中的一种。
    初始时,拥有其中M种作物的种子(数量无限,可以支持多次杂交)。同时可以进行多个杂交过程。求问对于给定的目标种子,最少需要多少天能够得到。
    如存在4种作物ABCD,各自的成熟时间为5天、7天、3天、8天。初始拥有AB两种作物的种子,目标种子为D,已知杂交情况为A× B → C,A xC →D。则最短的杂交过程为:
    第1天到第7天(作物B的时间),Ax B→C。第8天到第12天(作物A 的时间),A×C →D。花费12天得到作物D的种子。

    public class ZuoWuZaJiao {
    static int n, m, k, t;
    // 种植时间、初始作物种类、杂交所需的时间、植物是否已经合成、记录各类物种合成所需的最短时间
    static int[] time, staSeed, maxTime, visited, res;
    static int[][] hyb;// 杂交途径
    
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
    
        // 第一行数目
        n = scan.nextInt();// 作物种类
        m = scan.nextInt();// 初始作物种类
        k = scan.nextInt();// 杂交途径
        t = scan.nextInt();// 目标种子
        res = new int[n + 1];
        time = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            time[i] = scan.nextInt();
        }
        staSeed = new int[m];// 初始作物种类
        maxTime = new int[k];
        visited = new int[n + 1];
        for (int i = 0; i < m; i++) {
            staSeed[i] = scan.nextInt();
            visited[staSeed[i]] = 1;// 记录初始作物已合成
        }
        hyb = new int[k][3];
        for (int i = 0; i < k; i++) {
            hyb[i][0] = scan.nextInt();
            hyb[i][1] = scan.nextInt();
            hyb[i][2] = scan.nextInt();
            maxTime[i] = Math.max(time[hyb[i][0]], time[hyb[i][1]]);
        }
    
        System.out.println(dfs(t));
    }
    
    public static int dfs(int tar) {// kx:
        if (visited[tar] == 0) {// 未合成
            int min = Integer.MAX_VALUE;
            // 遍历杂交hyb
            for (int i = 0; i < k; i++) {
                if (hyb[i][2] == tar) {
                    min = Math.min(min, (maxTime[i] + Math.max(dfs(hyb[i][0]), dfs(hyb[i][1]))));
                }
            }
            visited[tar] = 1;
            res[tar] = min;
            return min;
        } else {
            return res[tar];
        }
    }
    }

    测试用例:I:6 2 4 6\n5 3 4 6 4 9\n1 2\n1 2 3\n1 3 4\n2 3 5\n4 5 6 ,O:16

  10. 子串分值

    对于一个字符串S,我们定义S的分值f(S)为S中恰好出现一次的字符个数。例如f("aba") =1,f("abc") = 3, f("aaa") =0。
    现在给定一个字符串S 0..n-1,请你计算对于所有S的非空子串 S[i..j](0 ≤i≤ j<n),f(S[i..j])的和是多少。

    public class ZiChuanFenZhi {
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            String str = sc.next();
            int len = str.length();
            int right, left, sum = 0;
    
            for (int i = 0; i < len; i++) {
                for (right = i + 1; right < len; right++) {
                    if (str.charAt(right) == str.charAt(i)) {
                        break;
                    }
                }
                for (left = i - 1; left >= 0; left--) {
                    if (str.charAt(left) == str.charAt(i)) {
                        break;
                    }
                }
                sum += (i - left) * (right - i);
            }
            System.out.print(sum);
            sc.close();
        }
    }

    测试用例:I:ababc ,O:21


第十二届 省赛(真题课件134)

  1. ASC

    已知大写字母 A 的 ASCII 码为 65,请问大写字母 L的 ASCII 码是多少?

    答案:76

    备注:就填数,直接秒了

  2. 空间

    小蓝准备用 256MB 的内存空间开一个数组,数组的每个元素都是 32 位进制整数,如果不考虑程序占用的空间和维护内存需要的辅助空间,请问256MB 的空间可以存储多少个 32 位二进制整数?

    public class KongJian {
    public static void main(String[] args) {
        System.out.print(256 >> 2 << 20);
    }
    }

    答案:67108864

    备注:纯数学计算就秒了,32位就是4B,256MB换算成B再除4,$256*2^{20}/4=2^{26}=$67108864

  3. 卡片

    小蓝有很多数字卡片,每张卡片上都是数字 0 到 9。
    小蓝准备用这些卡片来拼一些数,他想从 1 开始拼出正整数,每拼一个,就保存起来,卡片就不能用来拼其它数了。
    小蓝想知道自己能从 1 拼到多少。
    例如,当小蓝有 30 张卡片,其中 0到9各3张,则小蓝可以拼出 1到 10但是拼 11 时卡片 1 已经只有一张了,不够拼出 11。
    现在小蓝手里有 0 到9 的卡片各 2021 张,共 20210 张,请问小蓝可以从 1拼到多少?

    public class KaPian {
    public static void main(String[] args) {
        int sum=2021;
        int a1=0;
        for (int i = 1; i <= 20210; i++) {
            a1=i;
            while(a1>0) {
                if(a1%10==1&&sum>0) {
                    sum--;    
                }
                a1/=10;
            }
            if(sum==0) {
                System.out.println(i);
                break;
            }
        }
    }
    }

    答案:3181

  4. 相乘

    小蓝发现,他将 1 至 1000000007 之间的不同的数与 2021 相乘后再求除以1000000007 的余数,会得到不同的数。
    小蓝想知道,能不能在 1 至 1000000007 之间找到一个数,与 2021 相乘后再除以 1000000007 后的余数为 999999999。如果存在,请在答案中提交这个数:如果不存在,请在答案中提交 0。

    public class XiangCheng {
    public static void main(String[] args) {
        for(long i =1;i<=1000000007;i++) {
            if(((i*2021)%1000000007)==999999999) {
                System.out.println(i);
                break;
            }
        }
    }
    }

    答案:17812964

  5. 路径

    小蓝学习了最短路径之后特别高兴,他定义了一个特别的图,希望找到图中的最短路径。
    小蓝的图由 2021 个结点组成,依次编号 1 至 2021。
    对于两个不同的结点 a.b,如果 a 和 b的差的绝对值大于 21,则两个结点之间没有边相连:如果 a 和 b 的差的绝对值小于等于 21,则两个点之间有一条长度为 a 和 b 的最小公倍数的无向边相连。
    例如: 结点 1 和结点 23 之间没有边相连:结点 3 和结点 24 之间有一条无向边,长度为 24: 结点 15 和结点 25 之间有一条无向边,长度为 75。请计算,结点 1 和结点 2021 之间的最短路径长度是多少。

    public class LuJing {
    public static void main(String[] args) {
        int a = 21;
        for (int i = 21; i + 21 < 2021; i += 21) {
            a = a + i * (i + 21) / 21;
        }
        a = a + 2016 * 2021;
        System.out.println(a);
    }
    
    }

    答案:10266837

  6. 时间显示

    小蓝要和朋友合作开发一个时间显示的网站。在服务器上,朋友已经获取了当前的时间,用一个整数表示,值为从 1970 年 1 月 1 日 00:00:00 到当前时刻经过的毫秒数。
    现在,小蓝要在客户端显示出这个时间。小蓝不用显示出年月日,只需要显示出时分秒即可,毫秒也不用显示,直接舍去即可。
    给定一个用整数表示的时间,请将这个时间对应的时分秒输出。

    public class ShiJianXianShi {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        long n = scan.nextLong();
        n /= 1000;
        n %= (24 * 60 * 60);
        long hours = n / 3600;
        long minutes = n / 60 % 60;
        long seconds = n % 60;
        System.out.printf("%02d:%02d:%02d", hours, minutes, seconds);
        scan.close();
    }
    }

    测试用例:case 1:I:46800999 ,O:13:00:00 ;case 2:I:1618708103123 ,O:01:08:23

  7. 最少砝码

    你有一架天平。现在你要设计一套砝码,使得利用这些砝码可以称出任意小于等于 N 的正整数重量。
    那么这套砝码最少需要包含多少个砝码?
    注意砝码可以放在天平两边。

    public class ZuiShaoFaMa {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        scan.close();
        int number = 1;// 砝码数量,默认必须有砝码1
        int count = 1;// 砝码重量1,砝码每次递增都是*3
        int scope = 1;// 范围从1开始
        while (scope < n) {
            count *= 3; // count每次都是*3倍
            scope += count; // 范围数量都是加上当前的砝码重量
            number++;
        }
        System.out.println(number);
    }
    }

    测试用例:I:7 ,O:3

  8. 杨辉三角形

    如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如下数列:
    1, 1, 1, 1, 2, 1, 1, 3, 3, 1, 1, 4, 6, 4, 1, ...
    给定一个正整数 N,请你输出数列中第一次出现 N 是在第几个数?

    public class YangHuiSanJiaoXing {
    static long[] num = new long[44723];
    
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        long N = scan.nextLong();
        if (N == 1) {
            System.out.println(1);
            return;
        }
        num[1] = 1L;
        // dp计算
        for (int i = 2; i <= 44722; ++i) {
            for (int j = i; j >= 1; --j) {
                num[j] += num[j - 1];
                if (num[j] == N) {
                    /*
                     * 这里容易出错! 因为是下标从大到小的dp,杨辉三角是对称的,先满足的是对称轴右边的数 这里结果res的计算需要做一下对称处理,不是i*(i-1)/2 +j
                     * 实际上是第i行的第i-j+1个数首先满足相等条件
                     */
                    long res = (((long) i * ((long) i - 1)) >> 1) + i - j + 1;
                    System.out.println(res);
                    return;
                }
            }
        }
        // 此时,N一定是 第N+1行的第二个数
        long res = ((N * (N + 1)) >> 1) + 2;
        System.out.println(res);
    }
    }

    测试用例:I:6 ,O:13

  9. 左孩子右兄弟

    对于一棵多叉树,我们可以通过“左孩子右兄弟”表示法,将其转化成一棵二叉树。
    如果我们认为每个结点的子结点是无序的,那么得到的二叉树可能不唯一。换句话说,每个结点可以选任意子结点作为左孩子,并按任意顺序连接右兄弟。给定一棵包含 N 个结点的多叉树,结点从 1至 N 编号,其中 1 号结点是根,每个结点的父结点的编号比自己的编号小。请你计算其通过“左孩子右兄弟”表示法转化成的二叉树,高度最高是多少。注: 只有根结点这一个结点的树高度为 0。
    例如如下的多叉树:

    可能有以下 3 种(这里只列出 3 种,并不是全部) 不同的“左孩子右兄弟表示:

    其中最后一种高度最高,为 4。

    public class ZuoHaiZiYouXiongDi {
    static Map> map = new HashMap<>();
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        for (int i = 2; i <= n; i++) {
            int a = sc.nextInt();
            // 判断一个键在集合里面是否存在,如果不存在就将这个a添加到集合中
            map.putIfAbsent(a, new ArrayList<>());
            map.get(a).add(i);
        }
        int max = dsf(1);
        System.out.println(max);
    }
    
    public static int dsf(int x) {
        int sum = 0, max = 0;
        if (!map.containsKey(x)) {
            return 0;
        } else {
            List aa = map.get(x);
            sum = aa.size();
            for (Integer item : aa) {
                max = Math.max(dsf(item), max);
            }
            return sum + max;
        }
    }
    }

    测试用例:I:5\n1\n1\n1\n2 ,O:4

  10. 双向排序

    给定序列 $(a_1,a_2,...,a_n)=(1,2,...,n)$,即$a_i=i$
    小蓝将对这个序列进行 m 次操作,每次可能是将 $a_1,a2,...,a{qi}$降序排列或者将$a{qi},a{q_i+1},...,a_n$升序排列。
    请求出操作完成后的序列。

    public class ShuangXiangPaiXv {
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            int n = sc.nextInt(); // 接收n和m
            int m = sc.nextInt();
            Integer[] nums = new Integer[n + 1];
            for (int i = 1; i < n + 1; i++) { // 初始化所有数字
                nums[i] = i;
            }
            for (int i = 0; i < m; i++) {
                int p1 = sc.nextInt(), p2 = sc.nextInt();
                if (p1 == 0) // 若操作是0,则倒序排序
                    downSort(nums, p2 + 1);
                if (p1 == 1) // 若操作是1,则升序排序
                    upSort(nums, p2);
            }
            for (int i = 1; i < n + 1; i++) {
                System.out.print(nums[i] + " ");
            }
        }
    
        private static void upSort(Integer[] arr, int start) { // 升序排序方法
            Arrays.sort(arr, start, arr.length);
        }
    
        private static void downSort(Integer[] arr, int end) { // 降序排序方法
            Arrays.sort(arr, 1, end, Collections.reverseOrder());
        }
    }

    测试用例:I:3 3\n0 3\n1 2\n0 2 ,O:3 1 2


第十三届 省赛(真题课件143)

  1. 排列字母

    小蓝要把一个字符串中的字母按其在字母表中的顺序排列。例如,LANQIAO 排列后为 AAILNOQ。又如,GOODGOODSTUDYDAYDAYUP 排列后为 AADDDDDGGOOOOPSTUUYYY
    请问对于以下字符串,排列之后字符串是什么?

    WHERETHEREISAWILLTHEREISAWAY

    public class PaiLieZiMu {
    public static void main(String[] args) {                        java.util.Arrays.stream("WHERETHEREISAWILLTHEREISAWAY".split("")).sorted().forEach(System.out::print);
    }
    }

    答案:AAAEEEEEEHHHIIILLRRRSSTTWWWY

  2. 特殊时间

    2022 年 2 月 22 日 22:20 是一个很有意义的时间,年份为 2022,由3个2和 1个0组成,如果将月和日写成 4 位,为 0222,也是由3个2和1个0组成,如果将时间中的时和分写成 4 位,还是由 3 个 2 和 1个0 组成
    小蓝对这样的时间很感兴趣,他还找到了其它类似的例子,比如 111 年 10月 11 日 01:11,2202 年 2 月 22 日 22:02 等等。
    请问,总共有多少个时间是这种年份写成 4 位、月日写成 4 位、时间写成4 位后由 3 个一种数字和 1 个另一种数字组成。注意 1111 年 11 月 11 日 11:11不算,因为它里面没有两种数字。

    public class TeShuShiJian {
    public static void main(String[] args) {
        DateTimeFormatter d1 = DateTimeFormatter.ofPattern("MMdd");
           DateTimeFormatter d2 = DateTimeFormatter.ofPattern("HHmm");
           LocalDateTime start = LocalDateTime.of(0000, 01, 01, 00, 00);
           LocalDateTime end = LocalDateTime.of(0000, 12, 31, 23, 59);
           int[] buff = new int[128];
           int ans = 0;
           for (; start.compareTo(end) <= 0; start = start.plusMinutes(1)) {
               for (char i = '0'; i <= '9'; ++i) buff[i] = 0;
               for (byte b : start.format(d1).getBytes()) ++buff[b];
               boolean flag1 = true, flag3 = true;
               for (char i = '0'; i <= '9'; ++i)
                   if (buff[i] == 1) flag1 = false;
                   else if (buff[i] == 3) flag3 = false;
               if (flag1 || flag3) continue;
               for (byte b : start.format(d2).getBytes()) --buff[b];
               for (char i = '0'; i <= '9'; ++i)
                   if (buff[i] != 0) flag1 = true;
               if (!flag1) ++ans;
           }
           System.out.println(4 * ans);
    }
    }

    答案:212

  3. 纸张尺寸

    在 ISO 国际标准中定义了 A0 纸张的大小为 1189m x 841mm,将 AO 纸沿长边对折后为 A1 纸,大小为 841mm x 594mm,在对折的过程中长度直接取下整 (实际裁剪时可能有损耗)。将 A1 纸沿长边对折后为 A2 纸,依此类推。输入纸张的名称,请输出纸张的大小。

    public class ZhiZhangChiCun {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner sc = new Scanner(System.in);
        // A0尺寸
        int a = 1189;
        int b = 841;
        String c = sc.next();
        sc.close();
        for (int i = 0; i < c.charAt(1) - 48; i++) {
            if (a >= b) {
                a /= 2;
            } else {
                b /= 2;
            }
        }
        if (a >= b) {
            System.out.println(a);
        }
        System.out.println(b);
        if (a < b) {
            System.out.println(a);
        }
    }
    }

    测试用例:case 1:I:A0 ,O:1189\n841 ,case 2:I:A1 ,O:841\n594

  4. 求和

    给定 n 个整数 $a_1,a_2,...,a_n$ ,求它们两两相乘再相加的和,即$S=a_1a_2+a_1a_3+...+a_1a_n+a_2a3+...+a{n-2}a{n-1}+a{n-2}an+a{n-1}*a_n$

    public class QiuHe {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner sc = new Scanner(System.in);
        int a = sc.nextInt();
        int[] array = new int[a];
        long count = 0;
        for (int i = 0; i < array.length; i++) {
            array[i] = sc.nextInt();
        }
        sc.close();
        for (int i = 0; i < array.length; i++) {
            for (int j = i + 1; j < array.length; j++) {
                count += array[i] * array[j];
            }
        }
        System.out.println(count);
    }
    }

    测试用例:I:4\n1 3 6 9 ,O:117

  5. 矩形拼接

    已知 3 个矩形的大小依次是 $a_1b_1,a_2b_2$ 和 $a_3*b_3$。用这 3 个矩形能拼出的所有多边形中,边数最少可以是多少?
    例如用 3x2 的矩形(用A 表示)、4X1 的矩形(用 B 表示) 和2x4 的矩形 (用 c 表示) 可以拼出如下 4 边形。

    例如用 3x2 的矩形(用 A 表示)、3X1 的矩形(用 B 表示) 和 1X1的知形(用 c 表示) 可以拼出如下 6 边形。

    public class JvXingPinJie {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] b = new int[n];
        for (int i = 0; i < n; i++) {
            int[][] squares = new int[3][2];
            for (int j = 0; j < 3; j++) {
                squares[j][0] = sc.nextInt();
                squares[j][1] = sc.nextInt();
            }
            boolean matchingSides = false;
            for (int j = 0; j < 3; j++) {
                for (int k = 0; k < 3; k++) {
                    if (j != k && (squares[j][0] == squares[k][0] || squares[j][0] == squares[k][1]
                            || squares[j][1] == squares[k][0] || squares[j][1] == squares[k][1])) {
                        matchingSides = true;
                        break;
                    }
                }
                if (matchingSides) {
                    break;
                }
            }
    
            b[i] = matchingSides ? 4 : 6;
        }
        sc.close();
        for (int i = 0; i < n; i++) {
            System.out.println(b[i]);
        }
    }
    }

    测试用例:I:2\n2 3 4 1 2 4\n1 2 3 4 5 6 ,O:4\n6

  6. 选数异或

    给定一个长度为 n 的数列 $A_1,A_2,...,A_n$ 和一个非负整数 x,给定 m 次查询,每次询问能否从某个区间$[l,r]$中选择两个数使得他们的异或等于 x。

    public class XuanShuYiHuo {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int x = sc.nextInt();
        int a = 0;
        int dep[] = new int[n + 1];// 储存数列某个位置,至少存在一对数异或等于x的最大左下标。
        int map[] = new int[1 << 20];// 储存数列中任意一个元素的位置。大小为2^20
        for (int i = 1; i <= n; i++) {
            a = sc.nextInt();
            dep[i] = Math.max(dep[i - 1], map[a ^ x]);// 数列前一个元素也可能有满足条件的下标,取最大即可。
            map[a] = i;// 写在最后是防止有a^a=x,的可能出现。
            // 如果map[a^x]>a,由于还没有输入过a^x,所以map[a^x]实际上是默认值0
        }
        for (int j = 0; j < m; j++) {
            int l = sc.nextInt();
            int r = sc.nextInt();
            System.out.println(dep[r] >= l ? "yes" : "no");
        }
        sc.close();
    }
    }

    测试用例:I:4 4 1\n1 2 3 4\n1 4\n1 2\n2 3\n3 3 ,O:yes no yes no

    备注:输入时就会输出对应结果,继续按样例输入至程序结束即可

  7. GCD

    给定两个不同的正整数 a,b,求一个正整数 k 使得 gcd(a + k,b + k) 尽可能大,其中 gcd(a,b) 表示 a 和 b 的最大公约数,如果存在多个 k,请输出所有满足条件的 k 中最小的那个。

    public class GCD {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        long a = sc.nextLong();
        long b = sc.nextLong();
        sc.close();
        long max = Math.abs(a - b);
        System.out.print(max - (a % max));
    }
    }

    测试用例:I:5 7 ,O:1

  8. 青蛙过河

    小青蛙住在一条河边,它想到河对岸的学校去学习。小青蛙打算经过河里的石头跳到对岸。
    河里的石头排成了一条直线,小青蛙每次跳跃必须落在一块石头或者岸上。不过,每块石头有一个高度,每次小青蛙从一块石头起跳,这块石头的高度就会下降 1,当石头的高度下降到 0 时小青蛙不能再跳到这块石头上(某次跳跃后使石头高度下降到 0 是允许的)。
    小青蛙一共需要去学校上 天课,所以它需要往返 2x 次。当小青蛙具有个跳跃能力 y 时,它能跳不超过 y 的距离。
    请问小青蛙的跳跃能力至少是多少才能用这些石头上完 x 次课

    public class QingWaGuoHe {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        long x = sc.nextLong();
        long[] arr = new long[n + 1];
        for (int i = 1; i < n; i++) {
            arr[i] = sc.nextLong() + arr[i - 1];
        }
        sc.close();
        arr[n] = arr[n - 1] + 999999999999L;
        int l = 0;
        int sum = 0;
        for (int i = 1; i <= n; i++) {
            if (arr[i] - arr[l] >= 2L * x) {
                sum = Math.max(sum, i - l);
                l += 1;
            }
        }
        System.out.println(sum);
    }
    }

    测试用例:I:5 1\n1 0 1 0 ,O:4

  9. 因数平方和

    记f(x) 为x 的所有因数的平方的和。例如: $f(12)=1^2+2^2+3^2+4^2+6^2+12^2$
    定义 $g(n)=\sum_{i=1}^nf(i)$ 。给定 n,求 g(n) 除以 $10^9+7$ 的余数

    public class YinShuPingFangHe {
    public static void main(String[] args) {
        final long N = 1000000007;
        final long inv6 = 166666668;
        Scanner sc = new Scanner(System.in);
        long res = 0, temp = 0, sum = 0;
        long n, l, r, k;
        n = sc.nextInt();
        sc.close();
        for (long i = 1; i <= n; i = r + 1) {
            l = i;
            k = n / i;
            r = n / (n / l);
            temp = sum;
            sum = r * (r + (long) 1) % N * ((long) 2 * r + 1) % N * inv6 % N;
            res = (res + k * (sum - temp) + N) % N;
        }
    
        System.out.println(res);
    }
    }

    测试用例:I:100000 ,O:680584257

  10. 最长不下降子序列

    给定一个长度为 N 的整数序列: $A_1,A_2,...,A_N$。现在你有一次机会,将其中连续的 K 个数修改成任意一个相同值。请你计算如何修改可以使修改后的数列的最长不下降子序列最长,请输出这个最长的长度。
    最长不下降子序列是指序列中的一个子序列,子序列中的每个数不小于在它之前的数。

    public class ZuiChangBuXiaJiangZiXvLie {
        static int n_max = 1000000;
        static int[] arr = new int[n_max];
        static boolean[] c = new boolean[n_max];
        static long n, k;
    
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            n = sc.nextInt();
            k = sc.nextInt();
            c[0] = true;
            for (int i = 0; i < n; i++) {
                arr[i] = sc.nextInt();
            }
            sc.close();
            for (int i = 1; i < n; i++) {
                if (arr[i] < arr[i - 1]) {
                    c[i] = false;
                } else {
                    c[i] = true;
                }
            }
            int max = 0;
            for (int i = 0; i < n; i++) {
                if (k > 0) {
                    if (c[i]) {
                        max++;
                    } else {
                        k--;
                        max++;
                    }
                } else if (k == 0) {
                    if (c[i]) {
                        max++;
                    } else {
                        System.out.println(max);
                        break;
                    }
    
                }
            }
        }
    }

    测试用例:I:5 1\n1 4 2 8 5 ,O:4


第十四届 省赛(真题课件189)

  1. 求和

    求 1 (含) 至 20230408 (含)中每个数的和

    public class QiuHe {
    public static void main(String[] args) {
           System.out.println((long) (1 + 20230408) * (20230408 >>> 1));
       }
    }

    答案:204634714038436

  2. 分糖果

    两种糖果分别有 9 个和 16 个,要全部分给 7 个小朋友,每个小朋友得到的糖果总数最少为 2 个最多为 5 个,问有多少种不同的分法。糖果必须全部分
    只要有其中一个小朋友在两种方案中分到的糖果不完全相同,这两种方案就算作不同的方案。

    public class FenTangGuo {
    public static void main(String[] args) {
        dfs(1, 9, 16);
        System.out.println(sum);
    }
    
    static int sum = 0;
    
    static void dfs(int x, int a, int b) {
        if (x == 8) {
            if (a == 0 && b == 0) {
                // 如果七个人恰好分完则计数加一
                sum++;
            }
            return;
        }
    
        for (int i = 0; i <= a; i++) {
            for (int j = 0; j <= b; j++) {
                if (i + j >= 2 && i + j <= 5) {
                    // 只有满足2-5的条件才可以
                    dfs(x + 1, a - i, b - j);
                }
            }
        }
    }
    }

    答案:5067671

  3. 三国游戏

    小蓝正在玩一款游戏。游戏中魏蜀吴三个国家各自拥有一定数量的士兵x,yZ(一开始可以认为都为 0 )。游戏有 n 个可能会发生的事件,每个事件之间相互独立且最多只会发生一次,当第 i 个事件发生时会分别让 x,yZ 增加Ai, Bi, Ci
    当游戏结束时 (所有事件的发生与否已经确定),如果 xyZ 的其中一个大于另外两个之和,我们认为其获胜。例如,当 X >Y +Z 时,我们认为魏国获胜。小蓝想知道游戏结束时如果有其中一个国家获胜,最多发生了多少个事件?如果不存在任何能让某国获胜的情况,请输出 -1。

    public class SanGuoYouXi {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StreamTokenizer st = new StreamTokenizer(br);
    static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
    
    public static void main(String[] args) throws Exception {
        int n = nextInt();
        int[] a = new int[n];
        int[] b = new int[n];
        int[] c = new int[n];
        for (int i = 0; i < n; i++)
            a[i] = nextInt();
        for (int i = 0; i < n; i++)
            b[i] = nextInt();
        for (int i = 0; i < n; i++)
            c[i] = nextInt();
        for (int i = 0; i < n; i++) {
            int x = a[i], y = b[i], z = c[i];
            a[i] = x - y - z;
            b[i] = y - z - x;
            c[i] = z - x - y;
        }
        Arrays.sort(a);
        Arrays.sort(b);
        Arrays.sort(c);
        int s = 0;
        long sum = 0, ans = 0, count = 0;
        for (int i = n - 1; i >= 0; i--) {
            sum += a[i];
            ans += b[i];
            count += c[i];
            if (sum > 0 || ans > 0 || count > 0)
                s = n - i;
        }
        pw.println(s);
        pw.flush();
    }
    
    public static int nextInt() throws Exception {
        st.nextToken();
        return (int) st.nval;
    }
    
    public static long nextLong() throws Exception {
        st.nextToken();
        return (long) st.nval;
    }
    }

    测试用例:I:3 \n 1 2 2\n2 3 2\n1 0 7 ,O:2

  4. 平均

    有一个长度为 n 的数组 (n 是 10 的倍数),每个数 都是区间[0,9] 中的整数。小明发现数组里每种数出现的次数不太平均,而更改第 i个数的代价为b;,他想更改若干个数的值使得这 10 种数出现的次数相等(都等于 ),请问代价和最少为多少。

    public class PingJun {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StreamTokenizer st = new StreamTokenizer(br);
    static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
    
    public static void main(String[] args) throws Exception {
        int n = nextInt();
        int[][] f = new int[n][2];
        int[] d = new int[10];
        for (int i = 0; i < n; i++) {
            f[i][0] = nextInt();// 值
            f[i][1] = nextInt();// 价
        }
        Arrays.sort(f, ((a, b) -> {
            if (a[0] != b[0])
                return a[0] - b[0];
            return a[1] - b[1];
        }));
        long sum = 0;
        for (int i = n - 1; i >= 0; i--) {
            d[f[i][0]]++;
            if (d[f[i][0]] > n / 10)
                sum += f[i][1];
        }
        pw.println(sum);
        pw.flush();
    }
    
    public static int nextInt() throws Exception {
        st.nextToken();
        return (int) st.nval;
    }
    
    public static long nextLong() throws Exception {
        st.nextToken();
        return (long) st.nval;
    }
    }

    测试用例:I:10\n1 1\n1 2\n1 3\n2 4\n2 5\n2 6\n3 7\n3 8\n3 9\n4 10 ,O:27

  5. 填充

    有一个长度为 n 的 01 串,其中有一些位置标记为 ?,这些位置上可以任意填充 0 或者 1,请问如何填充这些位置使得这个 01 串中出现互不重叠的 00 和11 子串最多,输出子串个数。

    public class TianChong {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StreamTokenizer st = new StreamTokenizer(br);
    static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
    
    public static void main(String[] args) throws Exception {
        Scanner sc = new Scanner(System.in);
        String ss = sc.nextLine();
        boolean[] f = new boolean[ss.length() + 1];
        int count = 0;
        for (int i = 1; i < ss.length(); i++) {
            if (ss.charAt(i) == '?') {
                if (!f[i - 1]) {
                    count++;
                    f[i] = true;
                } else if (i != ss.length() - 1) {
                    count++;
                    f[i + 1] = true;
                    i++;
                }
            } else if (ss.charAt(i) == ss.charAt(i - 1) && !f[i - 1] || ss.charAt(i - 1) == '?' && !f[i - 1]) {
                count++;
                f[i] = true;
            }
        }
        pw.println(count);
        pw.flush();
    }
    
    public static int nextInt() throws Exception {// int型
        st.nextToken();
        return (int) st.nval;
    }
    
    public static long nextLong() throws Exception {// long型
        st.nextToken();
        return (long) st.nval;
    }
    }

    测试用例:I:1110?0 ,O:2

  6. 棋盘

    小蓝拥有 n xn 大小的棋盘,一开始棋盘上全都是白子。小蓝进行了 m 次操作,每次操作会将棋盘上某个范围内的所有棋子的颜色取反 (也就是白色棋子变为黑色,黑色棋子变为白色)。请输出所有操作做完后棋盘上每个棋子的颜色

    public class QiPan {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StreamTokenizer st = new StreamTokenizer(br);
    static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
    
    public static void main(String[] args) throws Exception {
        int n = nextInt();
        int m = nextInt();
        int[][] f = new int[n + 2][n + 2];
        for (int i = 0; i < m; i++) {
            int x1 = nextInt(), y1 = nextInt(), x2 = nextInt(), y2 = nextInt();
            for (int j = x1; j <= x2; j++) {
                f[j][y1]++;
                f[j][y2 + 1]--;
            }
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                f[i][j] += f[i][j - 1];
                if (f[i][j] % 2 == 0)
                    pw.print(0 + " ");
                else
                    pw.print(1 + " ");
            }
            pw.println();
        }
        pw.flush();
    }
    
    public static int nextInt() throws Exception {// int型
        st.nextToken();
        return (int) st.nval;
    }
    
    public static long nextLong() throws Exception {// long型
        st.nextToken();
        return (long) st.nval;
    }
    }

    测试用例:I:3 3\n1 1 2 2\n2 2 3 3\n1 1 3 3 ,O:0 0 1 \n0 1 0 \n1 0 0

  7. 子矩阵

    给定一个 nxm (n行 m列)的矩阵。
    设一个矩阵的价值为其所有数中的最大值和最小值的乘积。求给定矩阵的所有大小为 a x b (a 行 b 列)的子矩阵的价值的和。
    答案可能很大,你只需要输出答案对 998244353 取模后的结果

    public class ZiJvZhen {
    public static void main(String[] args) {
        int n = nextInt(), m = nextInt();
           int a = nextInt(), b = nextInt();
           long ans = 0;
           for (int i = 1; i <= n; ++i)
               for (int j = 1; j <= m; ++j)
                   matrix[i][j] = nextInt();
           Deque maxq = new ArrayDeque();
           Deque minq = new ArrayDeque();
           for (int j = 1; j <= m; ++j) {
               maxq.clear();
               minq.clear();
               for (int i = 1; i <= n; ++i) {
                   while (!maxq.isEmpty() && maxq.peekFirst() <= i - a) maxq.pollFirst();
                   while (!minq.isEmpty() && minq.peekFirst() <= i - a) minq.pollFirst();
                   while (!maxq.isEmpty() && matrix[i][j] >= matrix[maxq.peekLast()][j]) maxq.pollLast();
                   while (!minq.isEmpty() && matrix[i][j] <= matrix[minq.peekLast()][j]) minq.pollLast();
                   maxq.offerLast(i);
                   minq.offerLast(i);
                   max[i][j] = matrix[maxq.peekFirst()][j];
                   min[i][j] = matrix[minq.peekFirst()][j];
               }
           }
           for (int i = 1; i <= n; ++i) {
               maxq.clear();
               minq.clear();
               for (int j = 1; j <= m; ++j) {
                   while (!maxq.isEmpty() && maxq.peekFirst() <= j - b) maxq.pollFirst();
                   while (!minq.isEmpty() && minq.peekFirst() <= j - b) minq.pollFirst();
                   while (!maxq.isEmpty() && max[i][j] >= max[i][maxq.peekLast()]) maxq.pollLast();
                   while (!minq.isEmpty() && min[i][j] <= min[i][minq.peekLast()]) minq.pollLast();
                   maxq.offerLast(j);
                   minq.offerLast(j);
                   if (i >= a && j >= b)
                       ans = (ans + (long) max[i][maxq.peekFirst()] * min[i][minq.peekFirst()]) % 998244353;
               }
           }
           System.out.println(ans);
    }
    
       static int[][] matrix = new int[1001][1001];
    static int[][] max = new int[1001][1001];
    static int[][] min = new int[1001][1001];
    
       static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    
       static int nextInt() {
           try {
               in.nextToken();
           } catch (IOException e) {
               e.printStackTrace();
           }
           return (int) in.nval;
       }
    }

    测试用例:I:2 3 1 2\n1 2 3\n4 5 6 ,O:58

  8. 公因数匹配

    给定 n 个正整数 A;,请找出两个数 使得 i<j且 A;和 A存在大于 1的公因数。
    如果存在多组 i;j,请输出 i最小的那组。如果仍然存在多组 i.i,请输出 i最小的所有方案中 最小的那组。

    public class GongYinShuPiPei {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StreamTokenizer st = new StreamTokenizer(br);
    static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
    
    public static void main(String[] args) throws Exception {
        int n = nextInt();
        Map map = new HashMap<>();
        int min = 99999999, max = 0;
        int r = min, l = 0;
        for (int i = 0; i < n; i++) {
            int a = nextInt();
            int k = (int) (Math.sqrt(a) + 2);
    
            for (int j = 2; j <= k; j++) {
                if (a % j == 0 && a != j) {
                    if (map.get(j) == null)
                        map.put(j, i + 1);
                    else {
                        r = Math.min(r, map.get(j));
                        l = i + 1;
                    }
                    if (map.get(a / j) == null)
                        map.put(a / j, i + 1);
                    else {
                        r = Math.min(r, map.get(a / j));
                        l = i + 1;
                    }
                }
            }
            if (map.get(a) == null)
                map.put(a, i + 1);
            else if (a != 1) {
                r = Math.min(r, map.get(a));
                l = i + 1;
            }
            if (r != min) {
                min = r;
                max = l;
            }
        }
        pw.println(min + " " + max);
        pw.flush();
    }
    
    public static int nextInt() throws Exception {// int型
        st.nextToken();
        return (int) st.nval;
    }
    
    public static long nextLong() throws Exception {// long型
        st.nextToken();
        return (long) st.nval;
    }
    }

    测试用例:I:5\n5 3 2 6 9 ,O:2 4

  9. 异或和之差

    给定一个含有 n 个元素的数组 A;,你可以选择两个不相交的子段。求出这两个子段内的数的异或和的差值的最大值。

    public class YiHuoHeZhiCha {
    public static void main(String[] args) {
        int n = nextInt(), ans = 0;
        for (int i = 1; i <= n; ++i)
            A[i] = nextInt();
        Trie lt = new YiHuoHeZhiCha().new Trie(), rt = new YiHuoHeZhiCha().new Trie();
        lmin[0] = rmin[n + 1] = 0x3f3f3f3f;
        for (int i = 1, s = 0; i <= n; ++i) {
            lt.insert(s);
            s ^= A[i];
            lmax[i] = Math.max(lmax[i - 1], lt.xorMax(s));
            lmin[i] = Math.min(lmin[i - 1], lt.xorMin(s));
        }
        for (int i = n, s = 0; i >= 1; --i) {
            rt.insert(s);
            s ^= A[i];
            rmax[i] = Math.max(rmax[i + 1], rt.xorMax(s));
            rmin[i] = Math.min(rmin[i + 1], rt.xorMin(s));
        }
        for (int i = 1; i < n; ++i) {
            ans = Math.max(ans, rmax[i + 1] - lmin[i]);
            ans = Math.max(ans, lmax[i] - rmin[i + 1]);
        }
        System.out.println(ans);
    }
    
    static int[] A = new int[200001];
    static int[] lmax = new int[200002];
    static int[] lmin = new int[200002];
    static int[] rmax = new int[200002];
    static int[] rmin = new int[200002];
    
    class Trie {
        int high = 20;
        Node root = new Node();
        void insert(int x) {
            Node cur = root;
            for (int i = high; i >= 0; --i) {
                int bit = (x >> i) & 1;
                if (cur.ch[bit] == null)
                    cur.ch[bit] = new Node();
                cur = cur.ch[bit];
            }
        }
    
        int xorMax(int x) {
            int max = 0;
            Node cur = root;
            for (int i = high; i >= 0; --i) {
                int bit = (x >> i) & 1;
                if (cur.ch[bit ^ 1] != null) {
                    cur = cur.ch[bit ^ 1];
                    max |= 1 << i;
                } else {
                    cur = cur.ch[bit];
                }
            }
            return max;
        }
    
        int xorMin(int x) {
            int min = 0;
            Node cur = root;
            for (int i = high; i >= 0; --i) {
                int bit = (x >> i) & 1;
                if (cur.ch[bit] != null) {
                    cur = cur.ch[bit];
                } else {
                    min |= 1 << i;
                    cur = cur.ch[bit ^ 1];
                }
            }
            return min;
        }
    
        class Node {
            Node[] ch = new Node[2];
        }
    
    }
    
    static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    
    static int nextInt() {
        try {
            in.nextToken();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return (int) in.nval;
    }
    }

    测试用例:I:6\n1 2 4 9 2 7 ,O:14

  10. 太阳

    这天,小蓝在二维坐标系的点 (X,Y) 上放了一个太阳,看做点光源。他拿来了 m 条线段,将它们平行于 x 轴放置在了坐标系中,第i 条线段的左端点在 x,y,长度为飞。线段之间不会有重合或部分重合的情况(但可能出现端点相交)。小蓝想知道有多少条线段能被太阳照亮 (一条线段有长度大于 0的部分被照亮就算)。

    public class TaiYang {
        static Scanner sc = new Scanner(System.in);
        static int n = sc.nextInt();
        static int X = sc.nextInt();
        static int Y = sc.nextInt();
    
        public static void main(String[] args) {
            List list = new ArrayList<>();
            for (int i = 0; i < n; i++) {
                int x = sc.nextInt();
                int y = sc.nextInt();
                int l = sc.nextInt();
                list.add(new Triple(x, y, l));
            } // 将所有x,y,l读入list中
            list.sort(new Comparator() {
                @Override
                public int compare(Triple l1, Triple l2) {
                    return -Integer.compare(l1.y, l2.y);
                }
            }); // 以y从大到小排序
            double[] arr1 = new double[2 * n]; // 保持以y从大到小排序的顺序进行在x轴上的覆盖
            double[] arr2 = new double[2 * n]; // 以在x轴上的坐标值排序,方便二分查找
            int i = -1;
            for (Triple item : list) {
                arr1[++i] = arr2[i] = y0x(item.x, item.y);
                arr1[n + i] = arr2[n + i] = y0x(item.x + item.l, item.y);
            }
            Arrays.sort(arr2);
            boolean[] tree = new boolean[1 << 19]; // 将已覆盖的位置进行标记
            boolean f = false;
            int ans = 0;
            for (int j = 0; j < n; j++) {
                int l = Arrays.binarySearch(arr2, arr1[j]);
                int r = Arrays.binarySearch(arr2, arr1[j + n]);
                for (int k = l; k < r; k++) {
                    if (!tree[k]) {
                        tree[k] = true;
                        f = true;
                    }
                }
                if (f) {
                    ++ans;
                    f = false;
                }
            }
            System.out.println(ans);
        }
    
        public static double y0x(int x, int y) {
            if (x == X)
                return x;
            long a = (long) X * y;
            long b = (long) Y * x;
            return (b - a) / ((Y - y) * 1.0);
        } // 返回端点在x轴上的投影
    }
    
    class Triple {
        int x, y, l;
    
        public Triple(int x, int y, int l) {
            this.x = x;
            this.y = y;
            this.l = l;
        }
    }

    测试用例:I:3 10 2000000\n5 3 5\n6 2 4\n0 1 10 ,O:2


終わり

山水有相逢,我们江湖再见!じゃな~
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇
Theme Argon By solstice23