第六届蓝桥杯 2015年国赛真题 (Java 大学C组)

蓝桥杯 2015年决赛 Java大学C组

    • #1 机器人数目
    • #2 生成回文数
    • #3 空心菱形
    • #4 奇怪的数列
    • #5 密文搜索
    • #6 居民集会


希望决赛题目不搞我

先挂


#1 机器人数目

本题满分: 15分


问题描述

少年宫新近邮购了小机器人配件,共有3类,其中,
A类含有:8个轮子,1个传感器
B类含有: 6个轮子,3个传感器
C类含有:4个轮子,4个传感器

他们一共订购了100套机器人,收到了轮子600个,传感器280个。
根据这些信息请你计算:B类型机器人订购了多少个?


答案提交

请直接提交该整数,不要填写任何多余内容。


60


calcCode:

public class Main {

    public static void main(String[] args) throws IOException {
        for (int A = 0; A <= 100; A++)
            for (int B = 0; B <= 100; B++)
                for (int C = 0; C <= 100; C++) {
                    if (A + B + C == 100 && A * 8 + B * 6 + C * 4 == 600 && A + B * 3 + C * 4 == 280) {
                        System.out.println(B);
                        return;
                    }
                }
    }
}

暴力


#2 生成回文数

本题满分: 29分


问题描述

所谓回文数就是左右对称的数字,比如:
585,5885,123321…
当然,单个的数字也可以算作是对称的。

小明发现了一种生成回文数的方法:
比如,取数字19,把它与自己的翻转数相加:
19 + 91 = 110,如果不是回文数,就再进行这个过程:
110 + 011 = 121 这次是回文数了。

200以内的数字中,绝大多数都可以在30步以内变成回文数,只有一个数字很特殊,就算迭代了1000次,它还是顽固地拒绝回文!


答案提交

请你提交该顽固数字,不要填写任何多余的内容。


196


calcCode:

public class Test {

    public static void main(String[] args) {
        int num[] = new int[33554432], len = 0;
        for (int k = 10, step; k < 200; k++)  {
            java.util.Arrays.fill(num, 0, len, 0);
            num[0] = k;
            len = init(num, 1);
            for (step = 0; step < 1000; step++){
                echo(num, len);
                len = init(num, len);
                if (check(num, len)) break;
            }
            if (step == 1000) System.out.println(k);
        }
    }

    static int init(int[] num, int len) {
        for (int i = 0; i < len; i++) {
            if (num[i] >= 10) {
                if (i == len - 1) len++;
                num[i + 1] += num[i] / 10;
                num[i] %= 10;
            }
        }
        return len;
    }

    static void echo(int[]num, int len) {
        for (int i = 0, j = len - 1; i <= j; i++, j--)
            num[i] = num[j] = num[i] + num[j];
    }

    static boolean check(int[] num, int len) {
        for (int i = 0, j = len - 1; i <= j; i++, j--)
            if (num[i] != num[j]) return false;
        return true;
    }
}

#3 空心菱形

本题满分: 37分


问题描述

小明刚刚开发了一个小程序,可以打印出任意规模的空心菱形,规模为6时,如下图:

第六届蓝桥杯 2015年国赛真题 (Java 大学C组)_第1张图片
他一高兴,踢掉了电源,最后一次修改没有保存…
毛病出在划线的部分。
请你帮助小明分析程序,填写划线部分缺失的代码。

public class Main
{
	static String pr(int m, int n)
	{
		String s = "";
		for(int i=0; i<n; i++) s += " ";
		for(int i=0; i<m; i++) s = "*" + s + "*";
		return s;
	}
	
	static void f(int n)
	{
		String s = pr(1,n*2-1) + "\n";
	    String s2 = s;
	    	
		for(int i=1; i<n; i++){
			s = ____________________________________;  //填空位置
			s2 = s + s2 + s; 
		}
		
		System.out.print(s2);
	}
	
	public static void main(String[] args)
	{
		f(6);
	}
}

答案提交

注意:只填写缺少的内容,不要填写题面已有代码或说明性文字。


s.replaceAll("\\* | \\*", "**")

优雅


#4 奇怪的数列

时间限制: 1.0s 内存限制: 512.0MB 本题满分: 31 分


问题描述

从X星截获一份电码,是一些数字,如下:
13
1113
3113
132113
1113122113

YY博士经彻夜研究,发现了规律:
第一行的数字随便是什么,以后每一行都是对上一行“读出来”
比如第2行,是对第1行的描述,意思是:1个1,1个3,所以是:1113
第3行,意思是:3个1,1个3,所以是:3113

请你编写一个程序,可以从初始数字开始,连续进行这样的变换。


输入格式

第一行输入一个数字组成的串,不超过100位
第二行,一个数字n,表示需要你连续变换多少次,n不超过20


输出格式

输出一个串,表示最后一次变换完的结果。


测试样例1

Input:
5
7

Output:
13211321322115

code:

import java.io.*;
import java.util.ArrayDeque;
import java.util.Deque;

public class Main {

    static final int INF = 0x3F3F3F3F;

    public static void main(String[] args)   {
        PrintWriter out = new PrintWriter(System.out);
        Deque<Integer> pre = new ArrayDeque();
        Deque<Integer> now = new ArrayDeque();
        Deque tmp;
        int n = 0, c = splitNum();
        while (c >= '0' && c <= '9') {
            pre.offer(c & 0xf);
            c = getByte();
        }
        c = splitNum();
        while (c >= '0' && c <= '9') {
            n = n * 10 + (c & 0xf);
            c = getByte();
        }
        while (n-- > 0) {
            pre.offer(INF);
            int nowV, preV = pre.poll(), len = 1;
            do {
                nowV = pre.poll();
                if (nowV == preV) len++;
                else {
                    now.offer(len);
                    now.offer(preV);
                    preV = nowV;
                    len = 1;
                }
            } while (nowV != INF);
            if (n != 0) {
                tmp = pre;
                pre = now;
                now = tmp;
                now.clear();
            }
        }
        while (!now.isEmpty())
            out.print(now.poll());
        out.close();
    }

    static byte[] buff = new byte[16];
    static int next, blen;
    static int getByte() {
        if (next >= blen)
            try {
                next = 0;
                blen = System.in.read(buff);
            } catch (IOException e) {
                e.fillInStackTrace();
            }
        return buff[next++];
    }

    static int splitNum() {
        int c = getByte();
        while (c < '0' || c > '9') c = getByte();
        return c;
    }
}

#5 密文搜索

时间限制: 5.0s 内存限制: 512.0MB 本题满分: 77 分


问题描述

福尔摩斯从X星收到一份资料,全部是小写字母组成。
他的助手提供了另一份资料:许多长度为8的密码列表。
福尔摩斯发现,这些密码是被打乱后隐藏在先前那份资料中的。

请你编写一个程序,从第一份资料中搜索可能隐藏密码的位置。要考虑密码的所有排列可能性。


输入格式

输入第一行:一个字符串s,全部由小写字母组成,长度小于1024*1024
紧接着一行是一个整数n,表示以下有n行密码,1<=n<=1000
紧接着是n行字符串,都是小写字母组成,长度都为8


输出格式

一个整数, 表示每行密码的所有排列在s中匹配次数的总和。


测试样例1

Input:
aaaabbbbaabbcccc
2
aaaabbbb
abcabccc

Output:
4

Explanation:
第一个密码匹配了3次,第二个密码匹配了1次,一共4次。

对它使用hash吧

先打个质数表

public class Test {

    public static void main(String[] args) throws IOException {
        int[] HASH_TABLE = new int[128];
        HASH_TABLE['a'] = 2;
        agent: for (int i = 'b', n = 3; i <= 'z'; n += 2) {
            for (int k = 'a', g = (int)Math.sqrt(n); HASH_TABLE[k] <= g; k++)
                if (n % HASH_TABLE[k] == 0) continue agent;
            HASH_TABLE[i++] = n;
        }
        StringBuilder out = new StringBuilder("static final int[] HASH_TABLE = { ");
        for (int i = 0; i < 128; i++)
            out.append(HASH_TABLE[i] + ", ");
        System.out.println(out.replace(out.length() - 2, out.length(), "};"));
    }
}

code:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;

public class Main {

    static final int[] HASH_TABLE = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101 };

    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String str = in.readLine();
        if (str.length() < 8) {
            System.out.print(0);
            return;
        }
        Integer temp;
        long cur = 1, cnt = 0;
        int n = Integer.parseInt(in.readLine());
        HashMap<Long, Integer> map = new HashMap();
        while (n-- > 0) {
            String line = in.readLine();
            long key = 1;
            for (int i = 0; i < 8; i++)
                key *= HASH_TABLE[line.charAt(i)];
            Integer val = map.get(key);
            if (val == null) val = 0;
            map.put(key, val + 1);
        }
        for (int i = 0; i < 7; i++)
            cur *= HASH_TABLE[str.charAt(i)];
        for (int i = 7, hi = str.length(); i < hi; i++) {
            cur *= HASH_TABLE[str.charAt(i)];
            temp = map.get(cur);
            if (temp != null)
                cnt += temp;
            cur /= HASH_TABLE[str.charAt(i - 7)];
        }
        System.out.print(cnt);
    }
}

#6 居民集会

时间限制: 8.0s 内存限制: 512.0MB 本题满分: 111 分


问题描述

蓝桥村的居民都生活在一条公路的边上,公路的长度为L,每户家庭的位置都用这户家庭到公路的起点的距离来计算,第i户家庭距起点的距离为di。

每年,蓝桥村都要举行一次集会。今年,由于村里的人口太多,村委会决定要在4个地方举行集会,其中3个位于公路中间,1个位最公路的终点。

已知每户家庭都会向着远离公路起点的方向去参加集会,参加集会的路程开销为家庭内的人数ti与距离的乘积。

给定每户家庭的位置di和人数ti,请为村委会寻找最好的集会举办地:p1, p2, p3, p4 (p1<=p2<=p3<=p4=L),使得村内所有人的路程开销和最小。


输入格式

输入的第一行包含两个整数n, L,分别表示蓝桥村的家庭数和公路长度。
接下来n行,每行两个整数di, ti,分别表示第i户家庭距离公路起点的距离和家庭中的人数。


输出格式

输出一行,包含一个整数,表示村内所有人路程的开销和。


测试样例1

Input:
6 10
1 3
2 2
4 5
5 20
6 5
8 7

Output:
18

Explanation:
在距起点2, 5, 8, 10这4个地方集会,6个家庭需要的走的距离分别为1, 0, 1, 0, 2, 0,总的路程开销为1*3+0*2+1*5+0*20+2*5+0*7=18。

评测用例规模与约定

对于10%的评测数据,1<=n<=300。
对于30%的评测数据,1<=n<=2000,1<=L<=10000,0<=di<=L,di<=di+1,0<=ti<=20。
对于100%的评测数据,1<=n<=100000,1<=L<=1000000,0<=di<=L,di<=di+1,0<=ti<=1000000。


code:

import java.io.IOException;
import java.io.InputStream;

public class Main {

    public static void main(String[] args) {
        InputReader in = new InputReader(System.in);
        int n = in.nextInt(), l = in.nextInt();
        House[] houses = new House[n + 1];
        long[] buff = new long[n + 1];
        for (int i = 0; i < n; i++)
            houses[i] = new House(in.nextInt(), in.nextInt());
        if (houses[n - 1].d == l) n--;
        else houses[n] = new House(l, 0);
        int mid = (int)find(0, n, buff, houses, true);
        long res = find(0, mid, buff, houses, false) + find(mid + 1, n, buff, houses, false);
        System.out.print(res);
    }

    static long find(int l, int r, long[] buff, House[] houses, boolean resType) {
        int res = l;
        long min = 0x3f3f3f3f3f3f3f3fL, leftV = 0, rightV = 0;
        for (int i = l; i < r; i++)
            rightV += buff[i] = (houses[r].d - houses[i].d) * houses[i].t;
        for (int i = l; i < r; i++) {
            leftV = 0;
            rightV -= buff[i];
            for (int j = i - 1; j >= l; j--)
                leftV += (houses[i].d - houses[j].d) * houses[j].t;
            if (min > (leftV += rightV)) {
                min = leftV;
                res = i;
            }
        }
        return resType? res: min;
    }

    static class House {

        int d, t;

        House(int d, int t) {
            this.d = d;
            this.t = t;
        }
    }

    static class InputReader {

        private InputStream in;
        private int next, len;
        private byte[] buff;

        InputReader(InputStream in) { this(in, 8192); }

        InputReader(InputStream in, int buffSize) {
            this.buff = new byte[buffSize];
            this.next = this.len = 0;
            this.in = in;
        }

        private int getByte() {
            if (next >= len)
                try {
                    next = 0;
                    len = in.read(buff);
                    if (len == -1) return -1;
                } catch (IOException e) {
                    e.fillInStackTrace();
                }
            return buff[next++];
        }

        private int split() {
            int c = getByte();
            while (c <= 32 || c == 127) c = getByte();
            return c;
        }

        public int nextInt() {
            int n = 0, c = split();
            boolean flag = true;
            if (c == '-') {
                c = getByte();
                flag = false;
            }
            while (c >= '0'&& c <='9') {
                n = n * 10 + (c & 0xf);
                c = getByte();
            }
            return flag? n: -n;
        }
    }
}

先找到最优中点,然后折半枚举
这么做不大严谨但也不无道理

骗个三十分总可吧


你可能感兴趣的:(java)