【无标题】【思特奇杯·云上蓝桥-算法集训营】第1周

19201310程习恩

1题 跑步训练

问题描述
小明要做一个跑步训练,初始时,小明充满体力,体力值计为 10000。
如果小明跑步,每分钟损耗 600 的体力。
如果小明休息,每分钟增加 300 的体力。
体力的损耗和增加都是 均匀变化的。
小明打算跑一分钟、休息一分钟、再跑一分钟、再休息一分钟……如此循环。
如果某个时刻小明的体力到达 0,他就停止锻炼,
请问小明在多久后停止锻炼。
为了使答案为整数,请以秒为单位输出答案,答案中只填写数,不填写单位。
答案提交
3880
 

public class Test1 {
    public static void main(String[] args) {
        int strength = 10000;
        int second = 0;
        System.out.println(train(10000));
    }
    public static int train(int strength){
        int second = 0;
        while (strength > 0){
            for(int i = 0;i < 60;i++){
                strength-=10;
                second++;
                if(strength <= 0){
                    return second;
                }
            }
            for(int i = 0;i < 60;i++){
                strength+=5;
                second++;
            }
        }
        return second;
    }
}

2题 阶乘约数

问题描述

定义阶乘 n! = 1 × 2 × 3 × ··· × n 。

请问 100! ( 100 的阶乘)有多少个约数。

答案提交

39001250856960000

public class Test2 {
    public static void main(String[] args){
        int[] flag = new int[105];
        for (int i = 2; i <= 100; i++)
        {
            int tmp = i;
            for (int j = 2; j <= tmp/j; j++)
            {
                while (tmp % j == 0)
                {
                    flag[j]++;
                    tmp /= j;
                }
            }
            if(tmp>1)flag[tmp]++;
        }
        long ans = 1;
        for (int i = 1; i <= 100; i++)
        {
            ans = ans*(flag[i] + 1);
        }
 
        System.out.println(ans);
    }
}

3题 出栈次序
问题描述
X 星球特别讲究秩序,所有道路都是单行线。
一个甲壳虫车队,共 16 辆车,按照编号先后发车,夹在其它车流中,缓缓前行。
路边有个死胡同,只能容一辆车通过,是临时的检查站,如图所示。
X 星球太死板,要求每辆路过的车必须进入检查站,也可能不检查就放行,也可
能仔细检查。
如果车辆进入检查站和离开的次序可以任意交错。
那么,该车队再次上路后,可能的次序有多少种?
为了方便起见,假设检查站可容纳任意数量的汽车。
显然,如果车队只有 1 辆车,可能次序 1 种;2 辆车可能次序 2 种;3 辆车可能
次序 5 种。
现在足足有 16 辆车啊,亲!需要你计算出可能次序的数目。
答案提交
35357670
 

public class Test3 {
    public static void main(String[] args) {
        System.out.println(find(16, 0));
    }
    public static int find(int wait,int enter){
        if(wait == 0){
            return 1;
        }
        if(enter == 0){
            return find(wait - 1,1);
        }
        return find(wait - 1,enter + 1) + find(wait,enter - 1);
    }
}

4题 哥德巴赫分解

题目如下:
哥德巴赫猜想认为:不小于4的偶数都可以表示为两个素数的和。

你不需要去证明这个定理,但可以通过计算机对有限数量的偶数进行分解,验证是否可行。

实际上,一般一个偶数会有多种不同的分解方案,我们关心包含较小素数的那个方案。

对于给定数值范围,我们想知道这些包含较小素数方案中最大的素数是多少。

比如,100以内,这个数是19,它由98的分解贡献。

你需要求的是10000以内,这个数是多少?

答案提交

173

public class Q4 {
    public static void main(String[] args) {
        final int max = 10005;
        int res = 0;
 
        boolean[] isPrime = new boolean[max];
        int[] prime = new int[max];
 
        for (int i = 0; i < max; i++) {
            isPrime[i] = true;
        }
 
        for(int i = 2; i < 10000; i++){
            if(isPrime[i]){
                prime[++prime[0]] = i;
                for(int j = i + i; j < 10000; j += i){
                    isPrime[j] = false;
                }
            }
        }
 
        for(int i = 4; i < 10000; i += 2) {
            for(int j = 1;j <= prime[0]; j++) {
                int t= i- prime[j];
                if(t > 0 && isPrime[t]) {
                    res = Math.max(res, prime[j]);
                    break;
                }
            }
        }
 
        System.out.println(res);
    }
}

5题 图书排列
题目描述
将编号为 1~10 的 10 本书排放在书架上,要求编号相邻的书不能放在相邻的位
置。
请计算一共有多少种不同的排列方案。
注意,需要提交的是一个整数,不要填写任何多余的内容。
答案提交
479306
 

public class Test5 {
    static int res = 0;
    public static boolean check(int[] a)
    {
        int l = a.length;
        for(int i = 0; i < l - 1; i++)
        {
            if(Math.abs(a[i] - a[i + 1]) == 1)
            {
                return false;
            }
        }
        return true;
    }
    public static void swap(int[] a, int x, int y)
    {
        int temp = a[x];
        a[x] = a[y];
        a[y] = temp;
    }
    public static void sort(int[] a, int begin, int end)
    {
        if(begin == end)
        {
            if(check(a))
                res++;
        }
 
        for(int i = begin; i <= end; i++)
        {
            swap(a,begin,i);
            sort(a,begin+1,end);
            swap(a,begin,i);
        }
    }
    public static void main(String[] args) {
 
        int[] a ={1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        sort(a, 0, a.length-1);
        System.out.println(res);
    }
}

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

答案提交

3141

public class Test6 {
    public static void main(String[] args) {
        for(int banana = 6; ; banana += 5){
            int temp = banana;
            // 第一只猴子
            if(temp%5 == 1){
                temp = (temp - 1) / 5 * 4;
            }else{   
                continue;
            }
            // 第二只猴子
            if(temp % 5 == 2){
                temp = (temp - 2) / 5 * 4;
            }else{
                continue;
            }
            // 第三只猴子
            if(temp % 5 == 3){
                temp = (temp - 3) / 5 * 4;
            }else{
                continue;
            }
            // 第四只猴子
            if(temp % 5 == 4){
                temp = (temp - 4) / 5 * 4;
            }else{
                continue;
            }
            // 第二只猴子
            if(temp > 0 && temp % 5 == 0){
                System.out.println(banana);
                break;
            }
        }
    }
}

7题 稍小分数
回到小学 ----
真分数:分子小于分母的分数
既约分数:分子分母互质,也就是说最大公约数是 1
x 星球数学城的入口验证方式是:
屏幕上显示一个真分数,需要你快速地找到一个比它小的既约分数,要求这个
分数越大越好。
同时限定你的这个分数的分母不能超过 100 。
 

public class Test7 {
    public static void main(String[] args) {
        int a = 7;
        int b = 13;
 
        int m, n;
        int max_a = 0;
        int max_b = 1;
 
        for(n = 100; n > 1; n--){
            for(m = n-1; m >= 1; m--){
                if(m * b < a * n && gcd(m, n) == 1){
                    if(m * max_b > n * max_a){
                        max_a = m;
                        max_b = n;
                        break;
                    }
                }
            }
        }
 
        System.out.println(max_a + "/" + max_b);
    }
 
    public static int gcd(int a, int b){
        if(b == 0) return a;
        return gcd(b, a % b);
    }
}

8题 excel 地址
问题描述
Excel 单元格的地址表示很有趣,它使用字母来表示列号。
比如,
A 表示第 1 列,
B 表示第 2 列,
Z 表示第 26 列,
AA 表示第 27 列,
AB 表示第 28 列,
BA 表示第 53 列,
....
当然 Excel 的最大列号是有限度的,所以转换起来不难。
如果我们想把这种表示法一般化,可以把很大的数字转换为很长的字母序列
呢?
本题目即是要求对输入的数字, 输出其对应的 Excel 地址表示方式。
样例输入
26 样例输出
Z
样例输入
2054
样例输出
BZZ
 

public class Test8 {
    public static void main(String[] args) {
        long x, temp;
        int post = 0,i;
 
        Scanner sc = new Scanner(System.in);
        x = sc.nextInt();
 
        //判断整除小于最高位数
        for(i = 0; i < 20; i++){
            if((x / Math.pow(26, i)) < 1){
                post = i;
                break;
            }
        }
        int[] a= new int[post];
        for (int j = 0; j < post; j++) {
            a[j] = 0;
        }
        temp = x;
        //26进制化,只有1-26,没有0,存储方式是低位在左,高位在右
        for(i = 0; i < post; i++){
            a[i] = (int) (temp % 26);
            temp = temp / 26;
        }
        int j;
        //借用冒泡排序的方法实现借位思想
        //循环保证每次从低位到高位扫描不出现小于等于0的数
        for(i = 0; i < post; i++){
            for(j = i; j < post; j++){
                if(a[j] <= 0){
                    if(j == post - 1 && a[j] == 0){
                        continue;//最高位原来如果为1,借位变成0,最高位不用变
                    }
                    a[j + 1] = a[j+1] - 1;
                    a[j]= 26 + a[j];
                }
            }
        }
        int flag = 0;
        //从后往前输出
        for(i = post - 1; i >= 0; i--){
            if(a[i] != 0 || flag == 1){
                flag = 1;
                System.out.print((char)('A'+a[i]-1));
            }
        }
    }
}

9题 日期问题
小明正在整理一批历史文献。这些历史文献中出现了很多日期。小明知道这些日
期都在 1960 年 1 月 1 日至 2059 年 12 月 31 日。令小明头疼的是,这些日期采
用的格式非常不统一,有采用年/月/日的,有采用月/日/年的,还有采用日/月/年
的。更加麻烦的是,年份也都省略了前两位,使得文献上的一个日期,存在很多
可能的日期与其对应。
比如 02/03/04,可能是 2002 年 03 月 04 日、2004 年 02 月 03 日或 2004 年 03
月 02 日。 给出一个文献上的日期,你能帮助小明判断有哪些可能的日期对其对应吗?
输入
一个日期,格式是"AA/BB/CC"。 (0 <= A, B, C <= 9)
输出
输出若干个不相同的日期,每个日期一行,格式是"yyyy-MM-dd"。多个日期按
从早到晚排列。
样例输入
02/03/04
样例输出
2002-03-04
2004-02-03
2004-03-02
 

public class Q9 {
    static ArrayList<Data> data = new ArrayList<>();
 
    public static void main(String[] args) {
 
        Scanner sc  = new Scanner(System.in);
        //把题目中给的数据进行分割处理
        String[] tmp = sc.nextLine().trim().split("/");
        //添加日期的所有可能组合情况
        data.add(new Data(Integer.parseInt(tmp[0]),Integer.parseInt(tmp[1]),Integer.parseInt(tmp[2])));
        data.add(new Data(Integer.parseInt(tmp[2]),Integer.parseInt(tmp[1]),Integer.parseInt(tmp[0])));
        data.add(new Data(Integer.parseInt(tmp[2]),Integer.parseInt(tmp[0]),Integer.parseInt(tmp[1])));
        //对日期去重
        wipeRepeat();
        //判断日期合法性
        check();
        //对合法的日期进行排序
        sort();
        //输出合法的日期
        for(Data d : data) {
            System.out.println(d.toString());
        }
    }
 
    //对合法日期进行排序
    static void sort() {
        for(int i = 0; i < data.size()-1; i++) {
            for(int j = i+1; j < data.size(); j++) {
                int year1 = data.get(i).year;
                int year2 = data.get(j).year;
                int month1 = data.get(i).month;
                int month2 = data.get(j).month;
                int day1 = data.get(i).day;
                int day2 = data.get(j).day;
                if(year1 > year2) {
                    change(i,j);
                }else if(year1 == year2) {
                    if(month1 > month2) {
                        change(i,j);
                    }else if(month1 == month2) {
                        if(day1 > day2) {
                            change(i,j);
                        }
                    }
                }
            }
        }
    }
 
    //对两个合法的日期进行交换
    static void change(int i, int j) {
        Data temp = data.get(i);
        data.set(i, data.get(j));
        data.set(j, temp);
    }
 
    //判断日期的合法性
    static void check() {
        for(int i = 0; i < data.size(); i++) {
            int year = data.get(i).year;
            int month = data.get(i).month;
            int day = data.get(i).day;
            //月份在1-12之间
            if(month < 1 || month > 12) {
                data.remove(i);
                //迭代判断
                check();
                return ;
            }
            //大月有31天
            if(month == 1 || month == 3 || month == 5 || month == 7
                    || month == 8 || month == 10 || month == 12) {
                if(day < 1 || day > 31) {
                    data.remove(i);
                    //迭代判断合法性
                    check();
                    return ;
                }
            }
            //小月有30天
            if(month == 4 || month == 6 || month == 9 || month == 11) {
                if(day < 1 || day > 30) {
                    data.remove(i);
                    check();
                    return ;
                }
            }
            //闰年的2月为29天
            if(year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
                if(month == 2) {
                    if(day < 1 || day > 29) {
                        data.remove(i);
                        //迭代进行判断
                        check();
                        return ;
                    }
                }
            }
            //平年的2月有28天
            else {
                if(month == 2) {
                    if(day < 1 || day > 28) {
                        data.remove(i);
                        check();
                        return ;
                    }
                }
            }
        }
    }
 
 
    //去重方法
    static void wipeRepeat() {
        for(int i = 0; i < data.size(); i++) {
            for(int j = i+1; j < data.size(); j++) {
                if(data.get(i).year == data.get(j).year
                        && data.get(i).month == data.get(j).month
                        && data.get(i).day == data.get(j).day) {
                    data.remove(i);
                    //迭代去重
                    wipeRepeat();
                    return ;
                }
            }
        }
    }
 
}
 
class Data {
 
    int year;
    int month;
    int day;
 
    public Data(int year,int month,int day) {
        //这里确保年份在1960-2059之间
        if(year >= 60) {
            this.year = year + 1900;
        }else {
            this.year = year + 2000;
        }
        this.month = month;
        this.day = day;
    }
 
    //重写toString方法,日期格式化处理一下
    @Override
    public String toString() {
 
        if(month < 10 && day < 10)
            return year + "-0" + month + "-0" + day;
        else if(month < 10 && day >= 10)
            return year + "-0" + month + "-" + day;
        else if(month >= 10 && day < 10)
            return year + "-" + month + "-0" + day;
        else
            return year + "-" + month + "-" + day;
    }
 
}

对于一个正整数n的划分,就是把n变成一系列正整数之和的表达式。注意,分划与顺序无关,例如6=5+1.跟6=1+5是同一种分划,另外,这个整数本身也是一种分划。
例如:,对于正整数n=5,可以划分为:
1+1+1+1+1
1+1+1+2
1+1+3
1+2+2
2+3
1+4
5
输入描述
输入一个正整数n

输出描述
输出n整数划分的总数k

输入样例
5

输出样例
7
 

public class Test10 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        if(n >= 1) {
            System.out.println(Div(n,n));
        }
    }
 
    public static int Div(int n, int m){
        if(n == 1||m == 1)
            return 1;
        else if(n < m)
            return Div(n,n);
        else if(n == m)
            return 1+Div(n,n-1);
        else
            return Div(n,m-1) + Div(n-m,m);
    }
}

11题一步之遥
从昏迷中醒来,⼩明发现⾃⼰被关在 X 星球的废矿⻋⾥。
矿⻋停在平直的废弃的轨道上。
他的⾯前是两个按钮,分别写着“ F ”和“ B ”。
⼩明突然记起来,这两个按钮可以控制矿⻋在轨道上前进和后退。
按 F ,会前进 97 ⽶。按 B 会后退 127 ⽶。
透过昏暗的灯光,⼩明看到⾃⼰前⽅ 1 ⽶远正好有个监控探头。
他必须设法使得矿⻋正好停在摄像头的下⽅,才有机会争取同伴的援助。
或许,通过多次操作 F 和 B 可以办到。
矿⻋上的动⼒已经不太⾜,⻩⾊的警示灯在默默闪烁 ...
每次进⾏ F 或 B 操作都会消耗⼀定的能量。
⼩明⻜快地计算,⾄少要多少次操作,才能把矿⻋准确地停在前⽅ 1 ⽶远的地
⽅。
请填写为了达成⽬标,最少需要操作的次数。
注意,需要提交的是⼀个整数,不要填写任何⽆关内容(⽐如:解释说明等
答案提交
97
 

public class Test11 {
    static final int N = 1000;
 
    public static void main(String[] args) {
        int min=2*N+1;
        for(int B=0;B<=N;B++){
            for(int F=0;F<=N;F++){
                if(97*F-127*B==1){
                    if(F+B<min){
                        min=F+B;
                        System.out.println("F: " + F);
                        System.out.println("B: " + B);
                    }
                }
            }
        }
        System.out.println(min);;
    }
}

12题 X星球的机器⼈表演拉拉队有两种服装,A和B。
他们这次表演的是搭机器⼈塔。
类似:
A
B B
A B A
A A B B
B B B A B
A B A B B A
队内的组塔规则是:
A 只能站在 AA 或 BB 的肩上。
B 只能站在 AB 或 BA 的肩上。
你的任务是帮助拉拉队计算⼀下,在给定A与B的⼈数时,可以组成多少种花样
的塔。
输⼊⼀⾏两个整数 M 和 N,空格分开(0<M,N<500),分别表示A、B的⼈
数,保证⼈数合理性。
要求输出⼀个整数,表示可以产⽣的花样种数。
例如:
⽤户输⼊:
1 2
程序应该输出:
3
再例如: ⽤户输⼊:
3 3
程序应该输出:
4
 

public class Q12 {
    static final int N = 505;
    static int ans, m, n;
    static char[][] a = new char[N][N];
 
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        m = sc.nextInt();
        dfs(1,1,n,m);
        System.out.println(ans);
    }
 
    public static void dfs(int i, int j, int an, int am){
        if(an == 0 && am == 0) {
            ans++;
            return;
        }
        int x,y;
        if(i==j) {
            x = i + 1;
            y = 1;
        }
        else {
            x = i;
            y = j + 1;
        }
        if(j==1){
            if(an-1>=0){
                a[i][j]='A';
                dfs(x,y,an-1,am);
            }
            if(am-1>=0){
                a[i][j]='B';
                dfs(x,y,an,am-1);
            }
        }
        else {
            if(a[i-1][j-1]=='A'){
                if(a[i][j-1]=='B'){
                    if(am-1>=0){
                        a[i][j]='B';
                        dfs(x,y,an,am-1);
                    }
                }
                else {
                    if(an-1>=0){
                        a[i][j]='A';
                        dfs(x,y,an-1,am);
                    }
                }
            }
            else {
                if(a[i][j-1]=='B'){
                    if(an-1>=0){
                        a[i][j]='A';
                        dfs(x,y,an-1,am);
                    }
                }
                else {
                    if(am-1>=0){
                        a[i][j]='B';
                        dfs(x,y,an,am-1);
                    }
                }
            }
        }
    }
}

13题 七星填空
如下图所示。在七角星的 14 个节点上填入 1 ~ 14 的数字,不重复,不遗漏。
要求每条直线上的四个数字之和必须相等。
图片描述
图中已经给出了 3 个数字。 请计算其它位置要填充的数字,答案唯一。
填好后,请输出绿色节点的 4 个数字(从左到右,用空格分开)。
答案提交
10 3 9 8
 

public class Test13 {
    static int[] a = {1, 2, 3, 4, 5, 7, 8, 9, 10, 12, 13};
    static int [] b;
    static boolean[] c, d;
    public static void main(String[] args) {
        c = new boolean[14];
        d = new boolean[14];
        b = new int[14];
 
        b[0] = 6;
        b[8] = 14;
        b[10] = 11;
        c[0] = true;
        c[8] = true;
        c[10] = true;
 
        f(0);
    }
    private static void f(int i) {
        // 剪枝
        if (i == 9) {
            if (b[1] + b[2] + b[3] + b[4] != b[0] + b[2] + b[5] + b[8]) {
                return;
            }
        }
        if (i == 11) {
            if (b[1] + b[2] + b[3] + b[4] != b[0] + b[3] + b[6] + b[10]) {
                return;
            }
        }
        if (i == 12) {
            if (b[1] + b[2] + b[3] + b[4] != b[1] + b[5] + b[7] + b[11]) {
                return;
            }
        }
        if (i == 13) {
            if (b[1] + b[2] + b[3] + b[4] != b[9] + b[10] + b[11] + b[12]) {
                return;
            }
        }
        if (i == 14) {
            if (b[1] + b[2] + b[3] + b[4] != b[7] + b[8] + b[12] + b[13]) {
                return;
            }
            if (b[1] + b[2] + b[3] + b[4] != b[4] + b[6] + b[9] + b[13]) {
                return;
            }
            for (int j = 0; j < c.length; j++) {
                System.out.print(j==0 ? "" : " ");
                System.out.print(b[j]);
            }
            return;
        }
        if (!c[i]) {
            for (int j = 0; j < a.length; j++) {
                if (!d[j]) {
                    d[j] = true;
                    c[i] = true;
                    b[i] = a[j];
                    f(i + 1);
                    c[i] = false;
                    d[j] = false;
                }
            }
        } else {
            f(i + 1);
        }
    }
}

上一篇:Calendar的使用以及活动每月星期的信息


下一篇:Leetcode Mysql 1565. 按月统计订单数与顾客数(DAY 10)