蓝桥杯第四届省赛javaB组题目答案
第一题
标题: 世纪末的星期
曾有邪教称1999年12月31日是世界末日。当然该谣言已经不攻自破。
还有人称今后的某个世纪末的12月31日,如果是星期一则会…
有趣的是,任何一个世纪末的年份的12月31日都不可能是星期一!!
于是,“谣言制造商”又修改为星期日…
1999年的12月31日是星期五,请问:未来哪一个离我们最近的一个世纪末年(即xx99年)的12月31日正好是星期天(即星期日)
请回答该年份(只写这个4位整数,不要写12月31等多余信息)
2299
import java.util.Calendar;
public class N0_4_1 {
public static void main(String[] args) {
int i=1999;
while(true) {
i=i+100;
Calendar calendar=Calendar.getInstance();
calendar.set(i,11,31);
if(calendar.get(Calendar.DAY_OF_WEEK)-1==0) {
System.out.println(i);
return;
}
}
}
}
第二题
标题: 马虎的算式
小明是个急性子,上小学的时候经常把老师写在黑板上的题目抄错了。
有一次,老师出的题目是:36 x 495 = ?
他却给抄成了:396 x 45 = ?
但结果却很戏剧性,他的答案竟然是对的!!
因为 36 * 495 = 396 * 45 = 17820
类似这样的巧合情况可能还有很多,比如:27 * 594 = 297 * 54
假设 a b c d e 代表1~9不同的5个数字(注意是各不相同的数字,且不含0)
能满足形如: ab * cde = adb * ce 这样的算式一共有多少种呢?
请你利用计算机的优势寻找所有的可能,并回答不同算式的种类数。
满足乘法交换律的算式计为不同的种类,所以答案肯定是个偶数。
答案直接通过浏览器提交。
注意:只提交一个表示最终统计种类数的数字,不要提交解答过程或其它多余的内容。
142
public class NO_4_2 {
public static void main(String[] args) {
int count=0;
for(int a=1;a<10;a++) {
for(int b=1;b<10;b++) {
for(int c=1;c<10;c++) {
for(int d=1;d<10;d++) {
for(int e=1;e<10;e++) {
if(a!=b&&a!=c&&a!=d&&a!=e&&
b!=c&&b!=d&&b!=e&&
c!=d&&c!=e&&
d!=e&&(a*10+b)*(c*100+d*10+e)==(a*100+d*10+b)*(c*10+e)
)
{
count++;
}
}
}
}
}
}
System.out.println(count);
}
}
第三题
标题: 振兴中华
小明参加了学校的趣味运动会,其中的一个项目是:跳格子。
地上画着一些格子,每个格子里写一个字,如下所示:(也可参见p1.jpg)
从我做起振
我做起振兴
做起振兴中
起振兴中华
比赛时,先站在左上角的写着“从”字的格子里,可以横向或纵向跳到相邻的格子里,但不能跳到对角的格子或其它位置。一直要跳到“华”字结束。
要求跳过的路线刚好构成“从我做起振兴中华”这句话。
请你帮助小明算一算他一共有多少种可能的跳跃路线呢?
35
public class NO_4_3 {
static int count=0;
static int[][] array=new int[4][5];
public static void main(String[] args) {
for (int i= 0; i< 4; i++) {
for (int j = 0; j < 5; j++) {
array[i][j]=i+j;
}
}
dfs(0,0,0);
System.out.println(count);
}
public static void dfs(int i,int j,int value) {
System.out.println(i+", "+j);
if(array[i][j]!=value) {
return;
}
if(array[i][j]==value&&value==7){
count++;
}
if(i+1<4) {
//System.out.println(i+" "+j);
dfs(i+1,j,value+1);
}
if(j+1<5) {
dfs(i,j+1,value+1);
}
}
}
第四题
标题: 黄金连分数
黄金分割数0.61803… 是个无理数,这个常数十分重要,在许多工程问题中会出现。有时需要把这个数字求得很精确。
对于某些精密工程,常数的精度很重要。也许你听说过哈勃太空望远镜,它首次升空后就发现了一处人工加工错误,对那样一个庞然大物,其实只是镜面加工时有比头发丝还细许多倍的一处错误而已,却使它成了“近视眼”!!
言归正传,我们如何求得黄金分割数的尽可能精确的值呢?有许多方法。
比较简单的一种是用连分数:
1
黄金数 = ---------------------
1
1 + -----------------
1
1 + -------------
1
1 + ---------
1 + …
这个连分数计算的“层数”越多,它的值越接近黄金分割数。
请你利用这一特性,求出黄金分割数的足够精确值,要求四舍五入到小数点后100位。
小数点后3位的值为:0.618
小数点后4位的值为:0.6180
小数点后5位的值为:0.61803
小数点后7位的值为:0.6180340
(注意尾部的0,不能忽略)
你的任务是:写出精确到小数点后100位精度的黄金分割值。
注意:尾数的四舍五入! 尾数是0也要保留!
0.6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911374
public class NO_4_4 {
public static void main(String[] args) {
BigDecimal b1 = new BigDecimal(1);//初次参数分母
BigDecimal b2 = new BigDecimal(1);//不变的分子
List<BigDecimal> BD=new ArrayList<BigDecimal>();
BD.add(b1);
for(int i=0;i<10000;i++) {
//多次执行,使结果更精确
//将 (1+1/1) 当作一个对象存到一个集合,每次循环都执行1+(1/上次的对象),然后将这个结果转成新的对象放到集合中
BD.add(b2.divide((BD.get(BD.size()-1)).add(b2),110,BigDecimal.ROUND_DOWN));
}
System.out.println((BD.get(BD.size()-1)).setScale(100,BigDecimal.ROUND_DOWN));//设置最后的精确小数点的位数100位*/
}
}
第五题
标题:有理数类
有理数就是可以表示为两个整数的比值的数字。一般情况下,我们用近似的小数表示。但有些时候,不允许出现误差,必须用两个整数来表示一个有理数。
这时,我们可以建立一个“有理数类”,下面的代码初步实现了这个目标。为了简明,它只提供了加法和乘法运算。
class Rational
{
private long ra;
private long rb;
private long gcd(long a, long b){
if(b==0)
return a;
return gcd(b,a%b);
}
public Rational(long a, long b){
ra = a;
rb = b;
long k = gcd(ra,rb);
if(k>1){ //需要约分
ra /= k;
rb /= k;
}
}
// 加法
public Rational add(Rational x){
return new Rational(ra*x.rb+rb*x.ra,rb*x.rb); //填空位置
}
// 乘法
public Rational mul(Rational x){
return new Rational(ra*x.ra, rb*x.rb);
}
public String toString(){
if(rb==1) return "" + ra;
return ra + "/" + rb;
}
}
使用该类的示例:
Rational a = new Rational(1,3);
Rational b = new Rational(1,6);
Rational c = a.add(b);
System.out.println(a + “+” + b + “=” + c);
请分析代码逻辑,并推测划线处的代码,通过网页提交
注意:仅把缺少的代码作为答案,千万不要填写多余的代码、符号或说明文字!!
第六题
标题:三部排序
一般的排序有许多经典算法,如快速排序、希尔排序等。
但实际应用时,经常会或多或少有一些特殊的要求。我们没必要套用那些经典算法,可以根据实际情况建立更好的解法。
比如,对一个整型数组中的数字进行分类排序:
使得负数都靠左端,正数都靠右端,0在中部。注意问题的特点是:负数区域和正数区域内并不要求有序。可以利用这个特点通过1次线性扫描就结束战斗!!
以下的程序实现了该目标。
static void sort(int[] x)
{
int p = 0;
int left = 0;
int right = x.length-1;
while(p<=right){
if(x[p]<0){
int t = x[left];
x[left] = x[p];
x[p] = t;
left++;
p++;
}
else if(x[p]>0){
int t = x[right];
x[right] = x[p];
x[p] = t;
right--;
}
else{
p++;//代码填空位置
}
}
}
如果给定数组:
25,18,-2,0,16,-5,33,21,0,19,-16,25,-3,0
则排序后为:
-3,-2,-16,-5,0,0,0,21,19,33,25,16,18,25
请分析代码逻辑,并推测划线处的代码,通过网页提交
注意:仅把缺少的代码作为答案,千万不要填写多余的代码、符号或说明文字!!
第七题
标题:错误票据
某涉密单位下发了某种票据,并要在年终全部收回。
每张票据有唯一的ID号。全年所有票据的ID号是连续的,但ID的开始数码是随机选定的。
因为工作人员疏忽,在录入ID号的时候发生了一处错误,造成了某个ID断号,另外一个ID重号。
你的任务是通过编程,找出断号的ID和重号的ID。
假设断号不可能发生在最大和最小号。
要求程序首先输入一个整数N(N<100)表示后面数据行数。
接着读入N行数据。
每行数据长度不等,是用空格分开的若干个(不大于100个)正整数(不大于100000)
每个整数代表一个ID号。
要求程序输出1行,含两个整数m n,用空格分隔。
其中,m表示断号ID,n表示重号ID
例如:
用户输入:
2
5 6 8 11 9
10 12 9
则程序输出:
7 9
public class NO_4_7 {
static int[] hash=new int[100001];
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int N=scanner.nextInt();
int m=0,n=0;
int max=-1,min=100001;
String str=scanner.nextLine();
while(N--!=0) {
String strline=scanner.nextLine();
Scanner s=new Scanner(strline);
while(s.hasNextInt()) {
int t=s.nextInt();
min=Math.min(t, min);
max=Math.max(t, max);
hash[t]++;
}
}
for (int i = min; i <=max; i++) {
if(hash[i]==0) {
m=i;
}
if(hash[i]==2) {
n=i;
}
}
System.out.println(m+" "+n);
}
}
第八题
幸运数
幸运数是波兰数学家乌拉姆命名的。它采用与生成素数类似的“筛法”生成。
首先从1开始写出自然数1,2,3,4,5,6,…
1 就是第一个幸运数。
我们从2这个数开始。把所有序号能被2整除的项删除,变为:
1 _ 3 _ 5 _ 7 _ 9 …
把它们缩紧,重新记序,为:
1 3 5 7 9 … 。这时,3为第2个幸运数,然后把所有能被3整除的序号位置的数删去。注意,是序号位置,不是那个数本身能否被3整除!! 删除的应该是5,11, 17, …
此时7为第3个幸运数,然后再删去序号位置能被7整除的(19,39,…)
最后剩下的序列类似:
1, 3, 7, 9, 13, 15, 21, 25, 31, 33, 37, 43, 49, 51, 63, 67, 69, 73, 75, 79, …
本题要求:
输入两个正整数m n, 用空格分开 (m < n < 1000*1000)
程序输出 位于m和n之间的幸运数的个数(不包含m和n)。
例如:
用户输入:
1 20
程序输出:
5
例如:
用户输入:
30 69
程序输出:
8
public class NO_4_8 {
static int[] luck=new int[500000+1];
public static void Lucky(int start,int luck[],int len) {
int num=luck[start];
int k=start;
for(int j=k;j<len;j++) {
if(j%num!=0) {
luck[k++]=luck[j];
}
}
if(num<len) {
Lucky(start+1,luck,k);
}
}
public static void main(String[] args) {
int len=500000;
for (int i = 1; i <len; i++) {
luck[i]=2*i-1;
}
Lucky(2,luck,len);
Scanner input=new Scanner(System.in);
int m=input.nextInt();
int n=input.nextInt();
int count=0;
for(int a=1;a<len;a++) {
if(luck[a]>=n || luck[a]==luck[a-1]) {
break;
}
if(luck[a]>m&&luck[a]<n) {
count++;
System.out.println(luck[a]);
}
}
System.out.println(count);
}
}
第九题
标题:带分数
100 可以表示为带分数的形式:100 = 3 + 69258 / 714
还可以表示为:100 = 82 + 3546 / 197
注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。
类似这样的带分数,100 有 11 种表示法。
题目要求:
从标准输入读入一个正整数N (N<1000*1000)
程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数。
注意:不要求输出每个表示,只统计有多少表示法!
例如:
用户输入:
100
程序输出:
11
再例如:
用户输入:
105
程序输出:
6
public class NO_4_9 {
static boolean[] book=new boolean[10];
static int[] a=new int[10];
static int kind=0;
static int sum(int start,int end) {
int sum=0;
for(int i=start;i<end;i++) {
sum=sum*10+a[i+1];
}
return sum;
}
static void check(int[] a,int n,int num) {
int temp=num,begin=1;
while((temp=temp/10)!=0) {
begin++;
}
for(int k=1;k<begin+1;k++) {
int num1=sum(0,k);
if(num1>num) {
return;
}
for(int j=k+(n-k)/2;j<n-1;j++) {
int num2=sum(k,j);
int num3=sum(j,n-1);
if(num2>num3 && num2%num3==0 &&num==num1+num2/num3)
{
// System.out.println(num+" = "+num1+"+"+num2+"/"+num3);
kind++;
}
}
}
}
static void dfs(int step,int n,int num) {
if(step==n) {
check(a,n,num);
}
else {
for(int i=1;i<n;i++) {
if(book[i]) {
continue;
}
a[step]=i;
book[i]=true;
dfs(step+1,n,num);
book[i]=false;
}
}
}
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int num=input.nextInt();
dfs(1,10,num);
System.out.println(kind);
}
}