第一题:
标题:平方十位数
由0~9这10个数字不重复、不遗漏,可以组成很多10位数字。
这其中也有很多恰好是平方数(是某个数的平方)。
比如:1026753849,就是其中最小的一个平方数。
请你找出其中最大的一个平方数是多少?
注意:你需要提交的是一个10位数字,不要填写任何多余内容。
public class Main {
public static void main(String[] args){
long aa=100000;
long bb;
while(true){
aa--;
bb=aa*aa;
if(p(bb)){
System.out.println(bb);
return;
}
}
}
public static boolean p(long aa){
char[] arr=String.valueOf(aa).toCharArray();
for(int i=0;i<9;i++){
for(int j=i+1;j<10;j++){
if(arr[i]==arr[j])
return false;
}
}
return true;
}
}
第一题很简单,不过考虑时间复杂度,会发现:如果是按照9876543210的数字作全排来循环判断得出结论,循环次数显然可能很大,并且判断一个数是否是一个整数的平方所用到的sqrt()方法的时间复杂度并不低——因为它是double类型,显然大大的增加了不必要的运算,而思考可以得出:其实可以通过另一种结论来找到答案——用基数作为循环,基数的平方作为判断依据更为恰当。
第二题:
标题:生命游戏
康威生命游戏是英国数学家约翰·何顿·康威在1970年发明的细胞自动机。
这个游戏在一个无限大的2D网格上进行。
初始时,每个小方格中居住着一个活着或死了的细胞。
下一时刻每个细胞的状态都由它周围八个格子的细胞状态决定。
具体来说:
0,1 死
2,3 活
4,5,6,7,8 死
3 活
1. 当前细胞为存活状态时,当周围低于2个(不包含2个)存活细胞时, 该细胞变成死亡状态。(模拟生命数量稀少)
2. 当前细胞为存活状态时,当周围有2个或3个存活细胞时, 该细胞保持原样。
3. 当前细胞为存活状态时,当周围有3个以上的存活细胞时,该细胞变成死亡状态。(模拟生命数量过多)
4. 当前细胞为死亡状态时,当周围有3个存活细胞时,该细胞变成存活状态。 (模拟繁殖)
当前代所有细胞同时被以上规则处理后, 可以得到下一代细胞图。按规则继续处理这一代的细胞图,可以得到再下一代的细胞图,周而复始。
例如假设初始是:(X代表活细胞,.代表死细胞)
.....
.....
.XXX.
.....
下一代会变为:
.....
..X..
..X..
..X..
.....
康威生命游戏中会出现一些有趣的模式。例如稳定不变的模式:
....
.XX.
.XX.
....
还有会循环的模式:
...... ...... ......
.XX... .XX... .XX...
.XX... .X.... .XX...
...XX. -> ....X. -> ...XX.
...XX. ...XX. ...XX.
...... ...... ......
本题中我们要讨论的是一个非常特殊的模式,被称作"Gosper glider gun":
......................................
.........................X............
.......................X.X............
.............XX......XX............XX.
............X...X....XX............XX.
.XX........X.....X...XX...............
.XX........X...X.XX....X.X............
...........X.....X.......X............
............X...X.....................
.............XX.......................
......................................
假设以上初始状态是第0代,请问第1000000000(十亿)代一共有多少活着的细胞?
注意:我们假定细胞机在无限的2D网格上推演,并非只有题目中画出的那点空间。
当然,对于遥远的位置,其初始状态一概为死细胞。
注意:需要提交的是一个整数,不要填写多余内容。
166666713
参考代码:
import java.util.Scanner;
public class Main{
public static void main(String[] args){
char[][] arr1=new char[11][38];
Scanner in=new Scanner(System.in);
for(int i=0;i<11;i++){
arr1[i]=in.nextLine().toCharArray();
}
//以上为输入
char[][] arr2=new char[11][38];//arr1为当前细胞状态,arr2为下一个单位细胞状态
p(arr1,arr2,0);
}
public static void p(char[][] arr1,char[][] arr2,int k){
if(k==50){
return;
}//输出五十次
for(int i=0;i<11;i++){
for(int j=0;j<38;j++){
if(arr1[i][j]=='.'){
int count=0;
if(i>0){
if(arr1[i-1][j]=='X')
count++;
//上
if(j>0)
if(arr1[i-1][j-1]=='X')
count++;
//左上
if(j<37)
if(arr1[i-1][j+1]=='X')
count++;
//右上
}
if(j>0)
if(arr1[i][j-1]=='X')
count++;
if(j<37)
if(arr1[i][j+1]=='X')
count++;
if(i<10){
if(arr1[i+1][j]=='X')
count++;
//下
if(j>0)
if(arr1[i+1][j-1]=='X')
count++;
//左下
if(j<37)
if(arr1[i+1][j+1]=='X')
count++;
//右下
}
if(count==3)
arr2[i][j]='X';
else
arr2[i][j]='.';
}
//当细胞为死亡状态,判断他可否生长
if(arr1[i][j]=='X'){
int count=0;
if(i>0){
if(arr1[i-1][j]=='X')
count++;
//上
if(j>0)
if(arr1[i-1][j-1]=='X')
count++;
//左上
if(j<37)
if(arr1[i-1][j+1]=='X')
count++;
//右上
}
if(j>0)
if(arr1[i][j-1]=='X')
count++;
if(j<37)
if(arr1[i][j+1]=='X')
count++;
if(i<10){
if(arr1[i+1][j]=='X')
count++;
//下
if(j>0)
if(arr1[i+1][j-1]=='X')
count++;
//左下
if(j<37)
if(arr1[i+1][j+1]=='X')
count++;
//右下
}
if(count<2)
arr2[i][j]='.';
if(count>=2&&count<4)
arr2[i][j]='X';
if(count>=4)
arr2[i][j]='.';
}
//当为存活,判断他的下一单位时间状态
}
}
// for(int i=0;i<11;i++){
// for(int j=0;j<38;j++){
// System.out.print(arr2[i][j]);
// }
// System.out.println();
// }
// System.out.println();
//以上是输出每一个单位的细胞状态,好判断什么时候开始最外层细胞有存活——这个时候细胞总数量就不可靠了
int summ=0;
for(int i=0;i<11;i++){
for(int j=0;j<38;j++){
if(arr2[i][j]=='X')
summ++;
}
}
System.out.print(summ-36+" ");//输出每个单位时间增加的细胞数量
p(arr2,new char[11][38],k+1);
}
}
解析:这道题目前没想到正规的解题办法,目前使用的办法是把每一个单位时间的细胞图输出出来,同时也把每个单位时间的细胞总数输出出来——根据数据的分析得出结论——这个细胞繁殖是每繁殖30次总数加5的循环,于是可以得到结果——
166666713
第三题:
标题:树形显示
对于分类结构可以用树形来形象地表示。比如:文件系统就是典型的例子。
树中的结点具有父子关系。我们在显示的时候,把子项向右缩进(用空格,不是tab),并添加必要的连接线,以使其层次关系更醒目。
下面的代码就是为了这个目的的,请仔细阅读源码,并填写划线部分缺少的代码。
import java.util.*;
class MyTree
{
private Map<String, List<String>> map_ch = new HashMap<String, List<String>>();
private Map<String,String> map_pa = new HashMap<String,String>();
public void add(String parent, String child)
{
map_pa.put(child, parent);
List<String> lst = map_ch.get(parent);
if(lst==null){
lst = new ArrayList<String>();
map_ch.put(parent, lst);
}
lst.add(child);
}
public String get_parent(String me){
return map_pa.get(me);
}
public List<String> get_child(String me){
return map_ch.get(me);
}
private String space(int n)
{
String s = "";
for(int i=0; i<n; i++) s += ' ';
return s;
}
private boolean last_child(String x){
String pa = map_pa.get(x);
if(pa==null) return true;
List<String> lst = map_ch.get(pa);
return lst.get(lst.size()-1).equals(x);
}
public void show(String x){
String s = "+--" + x;
String pa = x;
while(true){
pa = map_pa.get(pa);
if(pa==null) break;
s = ___________________________________ ; // 填空
}
System.out.println(s);
}
public void dfs(String x){
show(x);
List<String> lst = map_ch.get(x);
if(lst==null) return;
for(String it: lst){
dfs(it);
}
}
}
public class TreeView
{
public static void main(String[] args)
{
MyTree tree = new MyTree();
tree.add("root", "dog");
tree.add("root", "cat");
tree.add("root", "duck");
tree.add("dog", "AAdog");
tree.add("dog", "BBdog");
tree.add("dog", "CCdog");
tree.add("AAdog", "AAdog01");
tree.add("AAdog", "AAdog02");
tree.add("cat", "XXcat");
tree.add("cat", "YYcat");
tree.add("XXcat","XXcat-oo");
tree.add("XXcat","XXcat-qq");
tree.add("XXcat-qq", "XXcat-qq-hahah");
tree.add("duck", "TTduck");
tree.add("TTduck", "TTduck-001");
tree.add("TTduck", "TTduck-002");
tree.add("TTduck", "TTduck-003");
tree.add("YYcat","YYcat.hello");
tree.add("YYcat","YYcat.yes");
tree.add("YYcat","YYcat.me");
tree.dfs("root");
}
}
对于题目中的测试数据,输出结果:
+--root
+--dog
| +--AAdog
| | +--AAdog01
| | +--AAdog02
| +--BBdog
| +--CCdog
+--cat
| +--XXcat
| | +--XXcat-oo
| | +--XXcat-qq
| | +--XXcat-qq-hahah
| +--YYcat
| +--YYcat.hello
| +--YYcat.yes
| +--YYcat.me
+--duck
+--TTduck
+--TTduck-001
+--TTduck-002
+--TTduck-003
+--root
+--dog
| +--AAdog
| | +--AAdog01
| | +--AAdog02
| +--BBdog
| +--CCdog
+--cat
| +--XXcat
| | +--XXcat-oo
| | +--XXcat-qq
| | +--XXcat-qq-hahah
| +--YYcat
| +--YYcat.hello
| +--YYcat.yes
| +--YYcat.me
+--duck
+--TTduck
+--TTduck-001
+--TTduck-002
+--TTduck-003
+--root
+--dog
| +--AAdog
| | +--AAdog01
| | +--AAdog02
| +--BBdog
| +--CCdog
+--cat
| +--XXcat
| | +--XXcat-oo
| | +--XXcat-qq
| | +--XXcat-qq-hahah
| +--YYcat
| +--YYcat.hello
| +--YYcat.yes
| +--YYcat.me
+--duck
+--TTduck
+--TTduck-001
+--TTduck-002
+--TTduck-003
如有平字体对齐问题,可以参见图【p1.png】
注意,只填写划线部分缺少的代码,不要抄写已有的代码或符号。
答案:(last_child(pa)?" ":"|")+space(4)+s
或者((pa=="root"||map_ch.get(map_pa.get(pa)).get(map_ch.get(map_pa.get(pa)).size()-1)==pa)?" ":"|")+space(map_ch.size()/2)+s
import java.util.*;
class MyTree
{
private Map<String, List<String>> map_ch = new HashMap<String, List<String>>();
private Map<String,String> map_pa = new HashMap<String,String>();
public void add(String parent, String child)//建立树
{
map_pa.put(child, parent);//在pa里添加一个节点,这个map里存放的是string类型对应string类型
List<String> lst = map_ch.get(parent);//在ch里添加一个节点,这个map里存放的是string对应集合string类型
if(lst==null){
lst = new ArrayList<String>();
map_ch.put(parent, lst);//在当前ch树里的当前节点新建出来一个集合来存放他的子节点,实现string对应集合string类型
}
lst.add(child);//把当前子节点存放到这个节点的集合里
}
public String get_parent(String me){//返回当前节点的父类
return map_pa.get(me);
}
public List<String> get_child(String me){//返回当前节点的所有子节点
return map_ch.get(me);
}
private String space(int n)//用来输出n个空格
{
String s = "";
for(int i=0; i<n; i++) s += ' ';
return s;
}
private boolean last_child(String x){//判断此节点是不是叶子节点,是不是叶子节点可以知道它前面需不需要输出"|"这个符号
String pa = map_pa.get(x);
if(pa==null) return true;//如果是就返回true,不是就执行后面的程序
List<String> lst = map_ch.get(pa);//把这个不是叶子节点的节点的子节点取出来
return lst.get(lst.size()-1).equals(x);//如果这个节点的子节点的最后一个子节点不是这个节点本身返回false,否则true
}
public void show(String x){//构造和输出
String s = "+--" + x;
String pa = x;
while(true){
pa = map_pa.get(pa);
if(pa==null) break;//没有子节点的时候结束当前这一分支的输出
s = (last_child(pa)?" ":"|")+space(4)+s;//每进入下一层深度,就需要在前面增加“ ”或者“|”增加哪个,在last_child里判断,然后再增加四个空格再加上本身的值,就是当前节点在这一行的所有符号了
// s = ((pa=="root"||map_ch.get(map_pa.get(pa)).get(map_ch.get(map_pa.get(pa)).size()-1)==pa)?" ":"|")+space(map_ch.size()/2)+s; // 填空
}
System.out.println(s);
}
public void dfs(String x){//用于递归输出每个节点
show(x);//先输出当前分支的根节点
List<String> lst = map_ch.get(x);
if(lst==null) return;
for(String it: lst){//然后输出当前根节点的所有子节点,如果其子节点也有子节点,先输出它(子节点)的子节点,然后再输出下一个子节点
dfs(it);
}
}
}
public class TreeView
{
public static void main(String[] args)
{
MyTree tree = new MyTree();
tree.add("root", "dog");
tree.add("root", "cat");
tree.add("root", "duck");
tree.add("dog", "AAdog");
tree.add("dog", "BBdog");
tree.add("dog", "CCdog");
tree.add("AAdog", "AAdog01");
tree.add("AAdog", "AAdog02");
tree.add("cat", "XXcat");
tree.add("cat", "YYcat");
tree.add("XXcat","XXcat-oo");
tree.add("XXcat","XXcat-qq");
tree.add("XXcat-qq", "XXcat-qq-hahah");
tree.add("duck", "TTduck");
tree.add("TTduck", "TTduck-001");
tree.add("TTduck", "TTduck-002");
tree.add("TTduck", "TTduck-003");
tree.add("YYcat","YYcat.hello");
tree.add("YYcat","YYcat.yes");
tree.add("YYcat","YYcat.me");
tree.dfs("root");
}
}
这道题是典型的树的构造与输出问题,也是真正难题的准备工作代码,
首先需要看清楚题目中给的输出格式,然后一点点弄清楚什么情况下输出多少空格,输不输出“|”,然后分析题中所有代码的作用。
代码看懂了,填空自然就知道答案了
至于为什么我写了两个答案。。。
因为第一次做题的时候太急,没有看到last_child和space这两个方法,于是在没有使用这两个本来就是为了提供给做题人减少做题人敲的代码量的这个情况下,,,居然把答案给弄出来了。
后来在写解析的时候,发现原来我还有last_child和space这两个方法没用到,于是立刻想到了最佳答案。尴尬,这时候才明白为什么当初我觉得这道题很难。。。简直不作死就不会死,做题真的不能急,越急越慢这句话完全体现出来了。
第四题:
标题:小计算器
模拟程序型计算器,依次输入指令,可能包含的指令有
1. 数字:'NUM X',X为一个只包含大写字母和数字的字符串,表示一个当前进制的数
2. 运算指令:'ADD','SUB','MUL','DIV','MOD',分别表示加减乘,除法取商,除法取余
3. 进制转换指令:'CHANGE K',将当前进制转换为K进制(2≤K≤36)
4. 输出指令:'EQUAL',以当前进制输出结果
5. 重置指令:'CLEAR',清除当前数字
指令按照以下规则给出:
数字,运算指令不会连续给出,进制转换指令,输出指令,重置指令有可能连续给出
运算指令后出现的第一个数字,表示参与运算的数字。且在该运算指令和该数字中间不会出现运算指令和输出指令
重置指令后出现的第一个数字,表示基础值。且在重置指令和第一个数字中间不会出现运算指令和输出指令
进制转换指令可能出现在任何地方
运算过程中中间变量均为非负整数,且小于2^63。
以大写的'A'~'Z'表示10~35
[输入格式]
第1行:1个n,表示指令数量
第2..n+1行:每行给出一条指令。指令序列一定以'CLEAR'作为开始,并且满足指令规则
[输出格式]
依次给出每一次'EQUAL'得到的结果
[样例输入]
7
CLEAR
NUM 1024
CHANGE 2
ADD
NUM 100000
CHANGE 8
EQUAL
[样例输出]
2040
补充说明:
1. n 值范围: 1<= n < 50000
2. 初始默认的进制是十进制
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。
import java.util.*;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Scanner;
public class Main{
public static void main(String[] args) throws Exception{
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
//使用reader流输入输出,因为考虑到输入的数据太大——事实上下载了蓝桥杯练习系统里这道题的输入量,确实吓到了,真他妈大,所以只能用了reader流——我之前用scanner显然超时
int n=Integer.parseInt(in.readLine());//n是指令数
long x=0;//x为计算器计算到当前时刻时得到的数据的值
String aa="";//aa为存储计算器上个指令需要计算器做加减乘除取余的哪一个运算
int k=10;//k存储计算器当前的进制数,10是默认为十进制
ArrayList<String> al=new ArrayList<String>();//存储每个输出指令输出的答案
for(;n>0;n--) {
String[] now=in.readLine().split(" ");//把数据分为指令和数字两类,数字可以没有,不影响
switch(now[0].substring(0,2)) {//根据指令的前两个字母,就可以知道这一指令需要做的是什么操作
case"NU":
long xx=0;
char[] an=now[1].toCharArray();//存储当前数据的字符串——因为数据很可能不是十进制所以需要以字符形式存储
long j=1;
for(int i=an.length-1;i>=0;i--,j*=k) {//进行进制转换,这个不做解释
if(an[i]>='A') {
xx+=(an[i]-'A'+10)*j;
}
else
xx+=(an[i]-'0')*j;
}
if(aa=="") {//如果上一指令不是加减乘除取余,那么直接存储数字即可
x=xx;
break;
}
else {//否则就需要对输入的数据进行aa运算
switch(aa){
case"AD":
x+=xx;
break;
case"SU":
x-=xx;
break;
case"MU":
x*=xx;
break;
case"DI":
x/=xx;
break;
case"MO":
x%=xx;
break;
}
aa="";//运算完毕需要对aa运算归零
}
break;
case"AD"://加减乘除存储到aa里,好知道下一个指令如果是数字,那么需要对存储数据和下一指令数字进行aa运算
aa="AD";
break;
case"SU"://
aa="SU";
break;
case"MU":
aa="MU";
break;
case"DI":
aa="DI";
break;
case"MO":
aa="MO";
break;
case"CH":
k=Integer.parseInt(now[1]);//存储需要转换的进制
break;
case"EQ"://输出的时候需要把当前数据改成规定的进制数据,至于为什么存储的数据是以十进制存储,当然是因为运算方便,但是输出不能的十进制,于是需要计算得到该值的字符串了
long y=x;
String answ="";
while(y!=0) {
int yu=(int)(y%k);
if(yu>=10) {
answ=(char)(yu-10+'A')+answ;
}
else
answ=(char)(yu+'0')+answ;
y/=k;
}//进制转换,不会的可以自己网上搜索,不讲解
if(answ=="")//考虑到可能输出的值是零,但是如果是零while是不循环的,也就是说al里会存储""而不是"0",所以需要加上这个if
al.add("0");
else
al.add(answ);
break;
case"CL"://当归零了,则需要去掉存储的数据和存储的加减乘除运算
x=0;
aa="";
break;
}
}
for(int i=0;i<al.size();i++) {
System.out.println(al.get(i));
}
}
}
这道题只考了一个进制转换的简单算法,所以算法不难,难在对数据和指令的处理上,解析写在代码里,这道题复杂,但是不难。
第五题:
标题:填字母游戏
小明经常玩 LOL 游戏上瘾,一次他想挑战K大师,不料K大师说:
“我们先来玩个空格填字母的游戏,要是你不能赢我,就再别玩LOL了”。
K大师在纸上画了一行n个格子,要小明和他交替往其中填入字母。
并且:
1. 轮到某人填的时候,只能在某个空格中填入L或O
2. 谁先让字母组成了“LOL”的字样,谁获胜。
3. 如果所有格子都填满了,仍无法组成LOL,则平局。
小明试验了几次都输了,他很惭愧,希望你能用计算机帮他解开这个谜。
本题的输入格式为:
第一行,数字n(n<10),表示下面有n个初始局面。
接下来,n行,每行一个串,表示开始的局面。
比如:“******”, 表示有6个空格。
“L****”, 表示左边是一个字母L,它的右边是4个空格。
要求输出n个数字,表示对每个局面,如果小明先填,当K大师总是用最强着法的时候,小明的最好结果。
1 表示能赢
-1 表示必输
0 表示可以逼平
例如,
输入:
4
***
L**L
L**L***L
L*****L
则程序应该输出:
0
-1
1
1
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。
第六题:
标题:区间移位
数轴上有n个闭区间:D1,...,Dn。
其中区间Di用一对整数[ai, bi]来描述,满足ai < bi。
已知这些区间的长度之和至少有10000。
所以,通过适当的移动这些区间,你总可以使得他们的“并”覆盖[0, 10000]——也就是说[0, 10000]这个区间内的每一个点都落于至少一个区间内。
你希望找一个移动方法,使得位移差最大的那个区间的位移量最小。
具体来说,假设你将Di移动到[ai+ci, bi+ci]这个位置。你希望使得maxi{|ci|} 最小。
【输入格式】
输入的第一行包含一个整数n,表示区间的数量。
接下来有n行,每行2个整数ai, bi,以一个空格分开,表示区间[ai, bi]。
保证区间的长度之和至少是10000。
【输出格式】
输出一个数字,表示答案。如果答案是整数,只输出整数部分。如果答案不是整数,输出时四舍五入保留一位小数。
【样例输入】
2
10 5010
4980 9980
【样例输出】
20
【样例说明】
第一个区间往左移动10;第二个区间往右移动20。
【样例输入】
4
0 4000
3000 5000
5001 8000
7000 10000
【样例输出】
0.5
【样例说明】
第2个区间往右移0.5;第3个区间往左移0.5即可。
【数据规模与约定】
对于30%的评测用例,1 <= n <= 10;
对于100%的评测用例,1 <= n <= 10000,0 <= ai < bi <= 10000。
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 2000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。