天天看點

第四屆藍橋杯JavaB組省賽真題

解題代碼部分來自網友,如果有不對的地方,歡迎各位大佬評論

題目1、世紀末星期

題目描述

曾有邪教稱1999年12月31日是世界末日。當然該謠言已經不攻自破。

還有人稱今後的某個世紀末的12月31日,如果是星期一則會…

有趣的是,任何一個世紀末的年份的12月31日都不可能是星期一!!

于是,“謠言制造商”又修改為星期日…

1999年的12月31日是星期五,請問:未來哪一個離我們最近的一個世紀末年(即xx99年)的12月31日正好是星期天(即星期日)?

請回答該年份(隻寫這個4位整數,不要寫12月31等多餘資訊)

解題思路

這裡用到了Java中的一個日期API——Calendar(1970年後的日期才可以使用這個API)

隻需從1999年開始每次增加100年周遊,看看對應世紀末年份12月31日是否為星期日即可停止周遊。

import java.util.Calendar;
 
public class Main {
 
	public static void main(String[] args) {
		Calendar calendar = Calendar.getInstance();
		for (int year = 1999; year < 10000; year += 100) {
			calendar.set(year, 11, 31);  // 注意0是代表1月份,是以12月份應該是11
			if (calendar.get(Calendar.DAY_OF_WEEK) == 1) {  // 這裡星期日為1,星期一為2...
				System.out.println(year);
				break;
			}
		}
	}
 
}
           

結果

2299

提示:題意中埋了一個坑,它說1999年的12月31日是星期五,這裡我們應該驗證一下實際中這天是否為星期五再去解題。

我們可以用calendar.set(1999, 11, 31);和System.out.println(calendar.get(Calendar.DAY_OF_WEEK));這兩句來看看輸出結果是否為6

巧解

其實這道題我們可以直接借助excel的内置函數來解決。

1、我們在A1單元格這裡輸入1999年12月31日

第四屆藍橋杯JavaB組省賽真題

2、選中B2這個單元格,在輸入框輸入=WEEKDAY(A1,2)然後回車。這裡第一個參數是想到得到對應星期的日期所在的單元格位置,第二個給2是為了,讓1代表星期一,2代表星期二等,這樣子友善看點。假如給1則1代表星期日了。

第四屆藍橋杯JavaB組省賽真題

3、在A2單元格中輸入2099年12月31日,然後選中A1和A2這兩個單元格往下拉。這樣A列就是每次增加100年的了。最後選中B1這個單元格往下拉,就能得出左邊對應日期所對應的星期了。

第四屆藍橋杯JavaB組省賽真題

這樣就得出了2299這個答案了。

題目2、馬虎的算式

題目描述

小明是個急性子,上國小的時候經常把老師寫在黑闆上的題目抄錯了。

有一次,老師出的題目是: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 這樣的算式一共有多少種呢?

請你利用計算機的優勢尋找所有的可能,并回答不同算式的種類數。

滿足乘法交換律的算式計為不同的種類,是以答案肯定是個偶數。

答案直接通過浏覽器送出。

注意:隻送出一個表示最終統計種類數的數字,不要送出解答過程或其它多餘的内容。

解題思路

直接用5重循環枚舉a、b、c、d、e,然後再湊出所需的數來進行驗證是否滿足條件即可。

解題代碼

public class Main {
 
	public static void main(String[] args) {
		int ans = 0;
		for (int a = 1; a <= 9; a++) {
			for (int b = 1; b <= 9; b++) {
				if (a != b)
					for (int c = 1; c <= 9; c++) {
						if (c != a && c != b)
							for (int d = 1; d <= 9; d++) {
								if (d != a && d != b && d != c)
									for (int e = 1; e <= 9; e++) {
										if (e != a && e != b && e != c && e != d) {
											if ((a * 10 + b) * (c * 100 + d * 10 + e) == (a * 100 + d * 10 + b)
													* (c * 10 + e)) {
												ans++;
											}
										}
									}
							}
					}
			}
		}
		System.out.println(ans);
	}
 
}
           

結果:142

題目3、振興中華

題目描述

小明參加了學校的趣味運動會,其中的一個項目是:跳格子。

地上畫着一些格子,每個格子裡寫一個字,如下所示:(也可參見p1.jpg)

從我做起振

我做起振興

做起振興中

起振興中華

比賽時,先站在左上角的寫着“從”字的格子裡,可以橫向或縱向跳到相鄰的格子裡,但不能跳到對角的格子或其它位置。一直要跳到“華”字結束。

要求跳過的路線剛好構成“從我做起振興中華”這句話。

請你幫助小明算一算他一共有多少種可能的跳躍路線呢?

答案是一個整數,請通過浏覽器直接送出該數字。

注意:不要送出解答過程,或其它輔助說明類的内容。

第四屆藍橋杯JavaB組省賽真題

解題思路

這是一道簡單的深搜題,我們可以把每個格子抽象為一個坐标,從(0,0),華(3,4)這樣。題意說橫向或縱向跳到相鄰的格子裡,但我們發現隻有向下走或者向右走才能達到要求,向上走或者想左走都不可能達到要求。是以在路線的總數為所在格子向下走的線路數和想右走的線路數的總和,當走到下邊界或者右邊界時,線路就已經确定了。

public class Main {
 
	public static void main(String[] args) {
		int ans = 0;
		ans = dfs(0, 0);
		System.out.println(ans);
	}
 
	public static int dfs(int i, int j) {
		if (i == 3 || j == 4) {
			return 1;
		}
		// dfs(i + 1, j):向下走的路線總數;dfs(i, j+ 1):向右走的路線總數
		return dfs(i + 1, j) + dfs(i, j + 1);
	}
}
           

結果:35

題目4、黃金連分數

題目描述

黃金分割數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也要保留!

顯然答案是一個小數,其小數點後有100位數字,請通過浏覽器直接送出該數字。

注意:不要送出解答過程,或其它輔助說明類的内容。

//用斐波納契數列和模拟手算除法實作

//黃金分割數實際上是相鄰的兩個斐波那契數的商

import java.math.BigInteger;

public class Main {
    public static void main(String[] args) {
        BigInteger firstNum = BigInteger.ONE; //1
        BigInteger secNum = BigInteger.ONE;
        BigInteger res = BigInteger.ZERO;   //0
        BigInteger TEN = BigInteger.TEN;   //10
        
        //BigInteger的斐波那契數列
        for (int i = 0; i < 50000; i++) {  
            if (i == 0 || i == 1) {
                res = BigInteger.ONE;
            }
            res = secNum.add(firstNum); //兩個BigInteger相加
            firstNum = secNum;
            secNum = res;
        }
        
        //for循環實作了模拟手算除法
        for (int i = 0; i < 101; i++) {
            //選擇斐波那契裡兩個連續的數,小的做被除數,大的做除數
            //每一位是兩者的商值
            BigInteger ans = firstNum.divide(secNum);
            //除數不變,被除數=餘數*10
            firstNum = (firstNum.mod(secNum)).multiply(TEN);
            if (i!=0) {  //隻輸出後面的100位小數點
                System.out.print(ans);    
            }
        }
        System.out.println();
        
    }
}
           

題目5、有理數類

題目描述
 有理數就是可以表示為兩個整數的比值的數字。一般情況下,我們用近似的小數表示。但有些時候,不允許出現誤差,必須用兩個整數來表示一個有理數。

 這時,我們可以建立一個“有理數類”,下面的代碼初步實作了這個目标。為了簡明,它隻提供了加法和乘法運算。

    public static void main(String[] args) {
        Rational a = new Rational(1,3);
        Rational b = new Rational(1,6);
        Rational c = a.add(b);
        System.out.println(a + "+" + b + "=" + c);
    }

    private static class Rational
    {
        private long ra;
        private long rb;

        //輾轉相除法求最大公約數gcd
        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+x.ra*rb, 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);


請分析代碼邏輯,并推測劃線處的代碼,通過網頁送出
注意:僅把缺少的代碼作為答案,千萬不要填寫多餘的代碼、符号或說明文字!!

           

題目6、三部排序

題目描述
一般的排序有許多經典算法,如快速排序、希爾排序等。

    但實際應用時,經常會或多或少有一些特殊的要求。我們沒必要套用那些經典算法,可以根據實際情況建立更好的解法。

    比如,對一個整型數組中的數字進行分類排序:

    使得負數都靠左端,正數都靠右端,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
    


請分析代碼邏輯,并推測劃線處的代碼,通過網頁送出
注意:僅把缺少的代碼作為答案,千萬不要填寫多餘的代碼、符号或說明文字!!

           

題目7、錯誤票據

題目描述

某涉密機關下發了某種票據,并要在年終全部收回。

每張票據有唯一的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

再例如:

使用者輸入:

6

164 178 108 109 180 155 141 159 104 182 179 118 137 184 115 124 125 129 168 196

172 189 127 107 112 192 103 131 133 169 158

128 102 110 148 139 157 140 195 197

185 152 135 106 123 173 122 136 174 191 145 116 151 143 175 120 161 134 162 190

149 138 142 146 199 126 165 156 153 193 144 166 170 121 171 132 101 194 187 188

113 130 176 154 177 120 117 150 114 183 186 181 100 163 160 167 147 198 111 119

則程式輸出:

105 120

資源約定:

峰值記憶體消耗(含虛拟機) < 64M

CPU消耗 < 2000ms

請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入…” 的多餘内容。

所有代碼放在同一個源檔案中,調試通過後,拷貝送出該源碼。

注意:不要使用package語句。不要使用jdk1.6及以上版本的特性。

注意:主類的名字必須是:Main,否則按無效代碼處理。

public class Main{
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		String[] s = new String[n];
		String[][] s1 = new String[n][];
		in.nextLine();
		for(int i=0; i<n; i++) {
			s[i] = in.nextLine();
			s1[i] = s[i].split(" ");
		}
		List<Integer> list = new ArrayList<Integer>();
		for(int i=0; i<n; i++)
			for(int j=0; j<s1[i].length; j++) {
				list.add(Integer.valueOf(s1[i][j]));
			}
		Collections.sort(list);
		int a=0,b=0;
		for(int i=0; i<list.size()-1; i++) {
			if(list.get(i+1)-list.get(i)==0) {
				a = list.get(i);
			}
			if(list.get(i+1)-list.get(i)==2) {
				b = list.get(i)+1;
			}
		}
		System.out.println(a+","+b);
	}
}
           

題目8、幸運數

題目描述

幸運數是波蘭數學家烏拉姆命名的。它采用與生成素數類似的“篩法”生成。

首先從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

資源約定:

峰值記憶體消耗(含虛拟機) < 64M

CPU消耗 < 2000ms

請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入…” 的多餘内容。

所有代碼放在同一個源檔案中,調試通過後,拷貝送出該源碼。

注意:不要使用package語句。不要使用jdk1.6及以上版本的特性。

注意:主類的名字必須是:Main,否則按無效代碼處理。

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
 
 
public class Main1 {
	public static void main(String[] args) {
		Scanner in=new Scanner(System.in);
		int n=in.nextInt();
		int m=in.nextInt();
		n=trans(n)-1;
		m=trans(m)-1;
		System.out.println((m-n));
		
	}
 
	private static int trans(int n) {
		// TODO 自動生成的方法存根
		if(n<3)return 2;
		List<Integer> list=new ArrayList<Integer>();
		for(int i=0;i<n;i++){
			list.add(i);
		}
		int luck=1;
		while(luck<n){
			if(list.size()<=luck)break; 
			int k;
			if(luck==1)k=2;
			else
			    k=list.get(luck);
			//System.out.print(k+"*");
			for(int i=list.size()-1;i>=k;i--){
				if(i%k==0)
					list.remove(i);
			}
			
			//System.out.println();
			luck++;
		}
//		for(int i=2;i<luck;i++){
//			System.out.print((list.get(i)-list.get(i-1))+" ");
//		}
//		System.out.println();
		
//		System.out.println("**"+luck);
		return luck;
	}
 
}
           

題目9、帶分數

題目描述

100 可以表示為帶分數的形式:100 = 3 + 69258 / 714

還可以表示為:100 = 82 + 3546 / 197

注意特征:帶分數中,數字1~9分别出現且隻出現一次(不包含0)。

類似這樣的帶分數,100 有 11 種表示法。

題目要求:

從标準輸入讀入一個正整數N (N<1000*1000)

程式輸出該數字用數位1~9不重複不遺漏地組成帶分數表示的全部種數。

注意:不要求輸出每個表示,隻統計有多少表示法!

例如:

使用者輸入:

100

程式輸出:

11

再例如:

使用者輸入:

105

程式輸出:

6

import java.util.Scanner;
 
public class Main {
	public static int cnt=0,num=0;
	public static boolean bool[]=new boolean[10];
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
        num=sc.nextInt();
        sc.close();
        for(int i=1;i<=7;i++)
        	for(int j=1;j<=7;j++)
        		if(9-i-j>=1)
        		{
        			dfs(0,0,0,i,j,9-i-j);
        		}
        System.out.println(cnt);
        
	}
	public static void dfs(int a,int b,int c,int alen,int blen,int clen)
	{
		if(alen==0&&blen==0&&clen==0)
		{
			if(b%c==0&&b/c==num-a)
			{
				cnt++;
			}
			return;
		}
		for(int i=1;i<10;i++)
		{
			if(!bool[i])
			{
				bool[i]=true;
				if(alen>0)
					dfs(a*10+i,b,c,alen-1,blen,clen);
				else if(blen>0)
					dfs(a,b*10+i,c,alen,blen-1,clen);
				else if(clen>0)
					dfs(a,b,c*10+i,alen,blen,clen-1);
				bool[i]=false;
			}
		}
	}
 
}
           

題目10、連号區間數

題目描述

小明這些天一直在思考這樣一個奇怪而有趣的問題:

在1~N的某個全排列中有多少個連号區間呢?這裡所說的連号區間的定義是:

如果區間[L, R] 裡的所有元素(即此排列的第L個到第R個元素)遞增排序後能得到一個長度為R-L+1的“連續”數列,則稱這個區間連号區間。

當N很小的時候,小明可以很快地算出答案,但是當N變大的時候,問題就不是那麼簡單了,現在小明需要你的幫助。
           

輸入格式:

第一行是一個正整數N (1 <= N <= 50000), 表示全排列的規模。

第二行是N個不同的數字Pi(1 <= Pi <= N), 表示這N個數字的某一全排列。

輸出格式:

輸出一個整數,表示不同連号區間的數目。

示例:

使用者輸入:

4

3 2 4 1

程式應輸出:

7

使用者輸入:

5

3 4 2 5 1

程式應輸出:

9

解釋:

第一個用例中,有7個連号區間分别是:[1,1], [1,2], [1,3], [1,4], [2,2], [3,3], [4,4]

第二個用例中,有9個連号區間分别是:[1,1], [1,2], [1,3], [1,4], [1,5], [2,2], [3,3], [4,4], [5,5]

資源約定:

峰值記憶體消耗(含虛拟機) < 64M

CPU消耗 < 5000ms

請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入…” 的多餘内容。

所有代碼放在同一個源檔案中,調試通過後,拷貝送出該源碼。

注意:不要使用package語句。不要使用jdk1.6及以上版本的特性。

注意:主類的名字必須是:Main,否則按無效代碼處理。

import java.util.Scanner;
 
public class Main {
 
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		int n=sc.nextInt();
		int[] a=new int[n];
		for(int i=0;i<n;i++)
		{
			a[i]=sc.nextInt();
		}
		int sum=0;
		for(int i=0;i<n;i++)
		{
			int min=a[i];
			int max=a[i];
			for(int j=i;j<n;j++)
			{
				if(a[j]>max)
					max=a[j];
				if(a[j]<min)
					min=a[j];
				if(max-min==j-i)
				{
					sum++;
				}
			}
		}
		System.out.println(sum);
 
	}
 
}