第八屆藍橋杯 b組試題解析

1.購物單
小明剛剛找到工作,老闆人很好,只是老闆夫人很愛購物。老闆忙的時候經常讓小明幫忙到商場代爲購物。小明很厭煩,但又不好推辭。
這不,XX大促銷又來了!老闆夫人開出了長長的購物單,都是有打折優惠的。
小明也有個怪癖,不到萬不得已,從不刷卡,直接現金搞定。
現在小明很心煩,請你幫他計算一下,需要從取款機上取多少現金,才能搞定這次購物。
取款機只能提供100元面額的紙幣。小明想盡可能少取些現金,夠用就行了。
你的任務是計算出,小明最少需要取多少現金。
以下是讓人頭疼的購物單,爲了保護隱私,物品名稱被隱藏了。

 180.90       88折
  10.25       65折
  56.14        9折
 104.65        9折
 100.30       88折
 297.15        半價
  26.75       65折
 130.62        半價
 240.28       58折
 270.62        8折
 115.87       88折
 247.34       95折
  73.21        9折
 101.00        半價
  79.54        半價
 278.44        7折
 199.26        半價
  12.97        9折
 166.30       78折
 125.50       58折
  84.98        9折
 113.35       68折
 166.57        半價
  42.56        9折
  81.90       95折
 131.78        8折
 255.89       78折
 109.17        9折
 146.69       68折
 139.33       65折
 141.16       78折
 154.74        8折
  59.42        8折
  85.44       68折
 293.70       88折
 261.79       65折
  11.30       88折
 268.27       58折
 128.29       88折
 251.03        8折
 208.39       75折
 128.88       75折
  62.06        9折
 225.87       75折
  12.89       75折
  34.28       75折
  62.16       58折
 129.12        半價
 218.37        半價
 289.69        8折

需要說明的是,88折指的是按標價的88%計算,而8折是按80%計算,餘者類推。
特別地,半價是按50%計算。
請提交小明要從取款機上提取的金額,單位是元。
答案是一個整數,類似4300的樣子,結尾必然是00,不要填寫任何多餘的內容。
特別提醒:不許攜帶計算器入場,也不能打開手機。

答案:52 。
思路:將數據處理一下 ,可以用記事本的替換功能 ,不用自己手動一個一個的處理 。下面是處理完以後的數據 。

#include <stdio.h>
int main()
{
	printf("%lf",  180.90 *0.88 
+10.25 *0.65 
+56.14 * 0.9 
+104.65 * 0.9 
+100.30 *0.88 
+297.15 * 0.5
+26.75 *0.65 
+130.62 * 0.5
+240.28 *0.58 
+270.62 * 0.8 
+115.87 *0.88 
+247.34 *0.95 
+73.21 * 0.9 
+101.00 * 0.5
+79.54 * 0.5
+278.44 * 0.7 
+199.26 * 0.5
+12.97 * 0.9 
+166.30 *0.78 
+125.50 *0.58 
+84.98 * 0.9 
+113.35 *0.68 
+166.57 * 0.5
+42.56 * 0.9 
+81.90 *0.95 
+131.78 * 0.8 
+255.89 *0.78 
+109.17 * 0.9 
+146.69 *0.68 
+139.33 *0.65 
+141.16 *0.78 
+154.74 * 0.8 
+59.42 * 0.8 
+85.44 *0.68 
+293.70 *0.88 
+261.79 *0.65 
+11.30 *0.88 
+268.27 *0.58 
+128.29 *0.88 
+251.03 * 0.8 
+208.39 *0.75 
+128.88 *0.75 
+62.06 * 0.9 
+225.87 *0.75 
+12.89 *0.75 
+34.28 *0.75 
+62.16 *0.58 
+129.12 * 0.5
+218.37 * 0.5
+289.69 * 0.8 
);
}

2.等差素數列
2,3,5,7,11,13,…是素數序列。
類似:7,37,67,97,127,157 這樣完全由素數組成的等差數列,叫等差素數數列。
上邊的數列公差爲30,長度爲6。
2004年,格林與華人陶哲軒合作證明了:存在任意長度的素數等差數列。
這是數論領域一項驚人的成果!
有這一理論爲基礎,請你藉助手中的計算機,滿懷信心地搜索:
長度爲10的等差素數列,其公差最小值是多少?
注意:需要提交的是一個整數,不要填寫任何多餘的內容和說明文字。
————————————————
答案:210 。
思路 :我們先生成一定範圍的素數 ,然後枚舉公差 ,枚舉起點 ,找到符合條件的序列 ,輸出公差即可 。

#include <stdio.h>
int a[1000000];
int ok(int x)
{
	for(int i=2;i*i<=x;i++)
	{
		if(x%i==0)
			return 0;
	}
	return 1;
}
void su()
{
	for(int i=2;i<1000000;i++)
	{
		if(ok(i))
			a[i]=1;
	}
}
int main()
{
	su();
	int flag=0;
	for(int d=1;d<100000;d++)  //枚舉公差 
	{
		for(int j=2;j<=100000;j++) //枚舉起點 
		{
			int t=0;
			for(int i=0;i<10;i++)
			{
				if(a[j+i*d])	{
					t++; 
					continue ;
				}
				else {
					break;
				}		
			 }	
			 if(t==10)	{
			 	flag=1;
			 	break;
			 }	 
		}
		if(flag)
		{
			printf("%d",d);
			break;
		}
	}
	return 0;
}

標題:承壓計算

X星球的高科技實驗室中整齊地堆放着某批珍貴金屬原料。

每塊金屬原料的外形、尺寸完全一致,但重量不同。
金屬材料被嚴格地堆放成金字塔形。

	                         7
                            5 8 
                           7 8 8 
                          9 2 7 2 
                         8 1 4 9 1 
                        8 1 8 8 4 1 
                       7 9 6 1 4 5 4 
                      5 6 5 5 6 9 5 6 
                     5 5 4 7 9 3 5 5 1 
                    7 5 7 9 7 4 7 3 3 1 
                   4 6 4 5 5 8 8 3 2 4 3 
                  1 1 3 3 1 6 6 5 5 4 4 2 
                 9 9 9 2 1 9 1 9 2 9 5 7 9 
                4 3 3 7 7 9 3 6 1 3 8 8 3 7 
               3 6 8 1 5 3 9 5 8 3 8 1 8 3 3 
              8 3 2 3 3 5 5 8 5 4 2 8 6 7 6 9 
             8 1 8 1 8 4 6 2 2 1 7 9 4 2 3 3 4 
            2 8 4 2 2 9 9 2 8 3 4 9 6 3 9 4 6 9 
           7 9 7 4 9 7 6 6 2 8 9 4 1 8 1 7 2 1 6 
          9 2 8 6 4 2 7 9 5 4 1 2 5 1 7 3 9 8 3 3 
         5 2 1 6 7 9 3 2 8 9 5 5 6 6 6 2 1 8 7 9 9 
        6 7 1 8 8 7 5 3 6 5 4 7 3 4 6 7 8 1 3 2 7 4 
       2 2 6 3 5 3 4 9 2 4 5 7 6 6 3 2 7 2 4 8 5 5 4 
      7 4 4 5 8 3 3 8 1 8 6 3 2 1 6 2 6 4 6 3 8 2 9 6 
     1 2 4 1 3 3 5 3 4 9 6 3 8 6 5 9 1 5 3 2 6 8 8 5 3 
    2 2 7 9 3 3 2 8 6 9 8 4 4 9 5 8 2 6 3 4 8 4 9 3 8 8 
   7 7 7 9 7 5 2 7 9 2 5 1 9 2 6 5 3 9 3 5 7 3 5 4 2 8 9 
  7 7 6 6 8 7 5 5 8 2 4 7 7 4 7 2 6 9 2 1 8 2 9 8 5 7 3 6 
 5 9 4 5 5 7 5 5 6 3 5 3 9 5 8 9 5 4 1 2 6 1 4 3 5 3 2 4 1 
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X 

其中的數字代表金屬塊的重量(計量單位較大)。
最下一層的X代表30臺極高精度的電子秤。

假設每塊原料的重量都十分精確地平均落在下方的兩個金屬塊上,
最後,所有的金屬塊的重量都嚴格精確地平分落在最底層的電子秤上。
電子秤的計量單位很小,所以顯示的數字很大。

工作人員發現,其中讀數最小的電子秤的示數爲:2086458231

請你推算出:讀數最大的電子秤的示數爲多少?

答案 :72665192664

思路:這題就是一個遞歸 或者說動態規劃 。我們需要先把這個金字塔的數儲存起來 ,怎麼儲存呢?通過題目我們知道 ,下面的每一項都和這個數肩上的兩個值有關 ,那麼我們可以這樣儲存 :在這裏插入圖片描述
然後通過遞歸,得到第三十層的每個數值 ,找出這一層中最大值和最小值 ,然後根據題目給的數值 ,根據比例得到最大值的示數 。

#include <stdio.h>
double a[35][35],aaa=-1,bbb=1e9;
double max(double  x,double  y)
{
	return x>y?x:y;
}
double min(double  x,double  y)
{
	return x<y?x:y;
}
int main()
{
	for(int i=1;i<=29;i++)
	{
		for(int j=1;j<=i;j++)
		{
			scanf("%lf",&a[i][j]);
		}
	}
	for(int i=2;i<=30;i++)
	{
		for(int j=1;j<=i;j++)
		{
			a[i][j]+=(a[i-1][j-1]+a[i-1][j])/2;
		}
	}
	for(int i=1;i<=30;i++)
	{
		aaa=max(aaa,a[30][i]);
		bbb=min(bbb,a[30][i]);
	}
	printf("%.0lf\n",aaa/bbb*2086458231);
	return 0;
}

4.方格分割
6x6的方格,沿着格子的邊線剪開成兩部分。
要求這兩部分的形狀完全相同。
如圖:p1.png, p2.png, p3.png 就是可行的分割法。
試計算:
包括這3種分法在內,一共有多少種不同的分割方法。
注意:旋轉對稱的屬於同一種分割法。

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
答案:509 。

思路: 這個題第一次見但可能會有點蒙 ,我們應該怎麼形成兩個完全對稱的圖形呢?我們應該沿着線走 ,枚舉點 。仔細分析應該可以發現 ,如果兩個圖形對稱的話,那麼必過點(3,3)。那麼我們從(3,3)開始走 ,每次走兩個完全相反的方向 ,每當走到邊緣的時候 ,就會形成兩個對稱的圖形 。想到這裏 ,題就解決了 。題目說的旋轉重複的情況 ,我們除以4即可 。

#include <stdio.h>
int next[4][2]={0,1,1,0,0,-1,-1,0};  
int a[7][7];
long long ans;
void dfs(int x1,int y1,int x2,int y2)
{
	if((!x1||!y1)||(!x2||!x2)||x1==6||x2==6||y1==6||y2==6) 
	{
		ans++;
		return ;
	}
	int tx1,tx2;
	int ty1,ty2;
	for(int i=0;i<4;i++)
	{
		tx1=x1+next[i][0];
		ty1=y1+next[i][1];
		tx2=x2+next[(i+2)%4][0];
		ty2=y2+next[(i+2)%4][1];
		if(tx1==tx2&&ty1==ty2)	continue ;
		if(!a[tx1][ty1]&&!a[tx2][ty2]&&tx1>=0&&tx2>=0&&ty1>=0&&ty2>=0&&tx1<7&&tx2<7&&ty1<7&&ty2<7)
		{
			a[tx1][ty1]=1;
			a[tx2][ty2]=1;	
			dfs(tx1,ty1,tx2,ty2);
			a[tx1][ty1]=0;
			a[tx2][ty2]=0;	
		 } 
	}
}
int main()
{
	a[3][3]=1;
	dfs(3,3,3,3);
	printf("%lld",ans/4);
	return 0;
}

5.取數位
求1個整數的第k位數字有很多種方法。
以下的方法就是一種。
/

/ 求x用10進製表示時的數位長度 
int len(int x){
if(x<10) return 1;
return len(x/10)+1;
}

// 取x的第k位數字
int f(int x, int k){
if(len(x)-k==0) return x%10;
return _____________________;  //填空
}

int main()
{
int x = 23574;
printf("%d\n", f(x,3));
return 0;
}

對於題目中的測試數據,應該打印5。
請仔細分析源碼,並補充劃線部分所缺少的代碼。
注意:只提交缺失的代碼,不要填寫任何已有內容或說明性的文字。

答案 :f(x/10,k) .
思路 :這題應該不難想吧 。當剩下的位數不等於k的時候 ,除以十 。直到符合條件 。
6.最大公共子串
最大公共子串長度問題就是:
求兩個串的所有子串中能夠匹配上的最大長度是多少。
比如:“abcdkkk” 和 “baabcdadabc”,
可以找到的最長的公共子串是"abcd",所以最大公共子串長度爲4。
下面的程序是採用矩陣法進行求解的,這對串的規模不大的情況還是比較有效的解法。
請分析該解法的思路,並補全劃線部分缺失的代碼。

#include <stdio.h>
#include <string.h>
#define N 256
int f(const char* s1, const char* s2)
{
int a[N][N];
int len1 = strlen(s1);
int len2 = strlen(s2);
int i,j;

memset(a,0,sizeof(int)*N*N);
int max = 0;
for(i=1; i<=len1; i++){
for(j=1; j<=len2; j++){
if(s1[i-1]==s2[j-1]) {
a[i][j] = __________________________;  //填空
if(a[i][j] > max) max = a[i][j];
}
}
}

return max;
}
int main()
{
printf("%d\n", f("abcdkkk", "baabcdadabc"));
return 0;
}

注意:只提交缺少的代碼,不要提交已有的代碼和符號。也不要提交說明性文字
答案 : a[i-1][j-1]+1

7.日期問題
小明正在整理一批歷史文獻。這些歷史文獻中出現了很多日期。小明知道這些日期都在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

思路:本題情況數很多 ,做法也有很多,說一種我覺得比較簡單的吧。首先,我們讀入三個整數 ,用scanf("%d/%d/%d",&a,&b,&c);的方式便可以把三個整數保存起來了 ,輸出的時候我們用printf("%02d-%02d-%02d",a,b,c);的方式,不足兩位的用零補齊。我們要做的就是從19600101開始枚舉,一直枚舉到20591231。判斷數據是否是一個合法的日期,然後再判斷讀入的a,b,c是否可以組成這個日期,如果可以,輸出日期即可 。

#include <stdio.h>
int ri[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int a,b,c;
int ok(int x,int y,int z)
{
	int tz;
	if(y>12)	return 0;     //月份不合法 
	if((x%4==0&&x%100!=0)||(x%400==0)) //閏年 
	{
		if(y==2)	tz=ri[2]+1;
		else tz=ri[y];
		if(z>tz||!z)	return 0; 
	}
	else
	{
		tz=ri[y];
		if(z>tz||!z)	return 0;
	}
	return 1;
 } 
int main()
{
	scanf("%d/%d/%d",&a,&b,&c); 
	for(int i=19600101;i<=20591231;i++)
	{
		int year =i/10000,month = i % 10000 / 100,day=i%100;
		if(ok(year ,month ,day))  //日期合法 
		{
		 if((a==year%100&&b==month&&c==day)||(a==month&&b==day&&c==year%100)||(a==day&&b==month&&c==year%100)) //年月日 月日年 日月年  
		 {
		 	printf("%02d-%02d-%02d\n",year,month,day);
		 }
		}
	}
	return 0;
}

8:包子湊數

小明幾乎每天早晨都會在一家包子鋪喫早餐。他發現這家包子鋪有N種蒸籠,其中第i種蒸籠恰好能放Ai個包子。每種蒸籠都有非常多籠,可以認爲是無限籠。

每當有顧客想買X個包子,賣包子的大叔就會迅速選出若干籠包子來,使得這若干籠中恰好一共有X個包子。比如一共有3種蒸籠,分別能放3、4和5個包子。當顧客想買11個包子時,大叔就會選2籠3個的再加1籠5個的(也可能選出1籠3個的再加2籠4個的)。

當然有時包子大叔無論如何也湊不出顧客想買的數量。比如一共有3種蒸籠,分別能放4、5和6個包子。而顧客想買7個包子時,大叔就湊不出來了。

小明想知道一共有多少種數目是包子大叔湊不出來的。

輸入

第一行包含一個整數N。(1 <= N <= 100)
以下N行每行包含一個整數Ai。(1 <= Ai <= 100)

輸出

一個整數代表答案。如果湊不出的數目有無限多個,輸出INF。

例如,
輸入:
2
4
5

程序應該輸出:
6

再例如,
輸入:
2
4
6

程序應該輸出:
INF

樣例解釋:
對於樣例1,湊不出的數目包括:1, 2, 3, 6, 7, 11。
對於樣例2,所有奇數都湊不出來,所以有無限多個。

思路 :可以用完全揹包來做,但是這裏介紹另一種思路。假設我們輸入的n個數,他們的最大公約數都不是1 。即 :他們都是偶數或者都是奇數 。那麼 ,肯定有無數多個數是湊不出來的 。直接輸出INF即可 。反之 ,我們找到n個數中最小的那個數 ,一旦我們所湊出來的連續數據長度等於這個最小數 ,那麼後面的所有數 ,都可以被湊出來了,對不對?想到這裏 ,本題就解決了 。

#include <stdio.h>
int a[105],b[1000005],flag,t=1e9,ans,n;
int gcd(int x,int y)
{
    return !y?x:gcd(y,x%y);
}
int min(int x,int y)
{
    return x<y?x:y;
}
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
        b[a[i]]=1;
        t=min(t,a[i]);
    }
    for(int i=0;i<n;i++)
    {
        for(int j=i+1;j<n;j++)
        {
            if(gcd(a[i],a[j])==1)
            {
                flag=1;
                break;
            }
        }
        if(flag)    break;
    }
    if(!flag)
    {
        printf("INF");
        return 0;
    }
    int p=0;
    for(int i=1;i<=1000000;i++)
    {
        if(b[i])
        {
            p++;
            for(int j=0;j<n;j++)
            {
                b[i+a[j]]=1;
            }
        }
        else
        {
            p=0;
            ans++;
        }
        if(p==t)    break;
    }
    printf("%d",ans);
    return 0;
}

9: 分巧克力

兒童節那天有K位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友們。
小明一共有N塊巧克力,其中第i塊是Hi x Wi的方格組成的長方形。

爲了公平起見,小明需要從這 N 塊巧克力中切出K塊巧克力分給小朋友們。切出的巧克力需要滿足:

  1. 形狀是正方形,邊長是整數
  2. 大小相同

例如一塊6x5的巧克力可以切出6塊2x2的巧克力或者2塊3x3的巧克力。

當然小朋友們都希望得到的巧克力儘可能大,你能幫小Hi計算出最大的邊長是多少麼?

輸入
第一行包含兩個整數N和K。(1 <= N, K <= 100000)
以下N行每行包含兩個整數Hi和Wi。(1 <= Hi, Wi <= 100000)
輸入保證每位小朋友至少能獲得一塊1x1的巧克力。

輸出
輸出切出的正方形巧克力最大可能的邊長。

樣例輸入:
2 10
6 5
5 6

樣例輸出:
2

思路:本題需要確定所能得到的最大邊長,使得生成的巧克力數量不少於k.考慮到本題數據範圍爲10的5次方,暴力超時,則應該採用二分查找答案的方法,如果此邊長可以生成的巧克力數量不低於k,則向上縮小搜索範圍(不妨理解爲尋找右邊界)。一個nm規格的矩形可以生產幾個aa規格的正方形呢?容易得出規律,應該爲(n/a)(m/a)塊*

#include <stdio.h>
int n,k,h[100005],w[100005],t=1;r=1e5+1,mid;
int ok(int x)
{
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        int a=h[i]/x;
        int b=w[i]/x;
        ans+=a*b;          //一個x*y的矩形能分成x/i*y/i個i*i的正方形
    }
    if(ans>=k)  return 1;
    return 0;
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&h[i],&w[i]);
    }
    while(t<r)        //二分查找符合要求的邊長
    {
        mid=(t+r)/2;
        if(ok(mid)) t=mid+1;
        else    r=mid;
    }
    printf("%d",t-1);
    return 0;
}

10: k倍區間

給定一個長度爲N的數列,A1, A2, … AN,如果其中一段連續的子序列Ai, Ai+1, … Aj(i <= j)之和是K的倍數,我們就稱這個區間[i, j]是K倍區間。

你能求出數列中總共有多少個K倍區間嗎?

輸入

第一行包含兩個整數N和K。(1 <= N, K <= 100000)
以下N行每行包含一個整數Ai。(1 <= Ai <= 100000)

輸出

輸出一個整數,代表K倍區間的數目。

例如,
輸入:
5 2
1
2
3
4
5

程序應該輸出:
6

思路:題幹要求我們求得是k的倍數區間,我們可以用s[i]儲存前i個數,用s[i]-s[j-1]表示區間【j,i】的和。然後我們利用兩層for循環枚舉區間範圍,尋找符合要求的區間。至此,問題似乎解決了,But題幹所給的數據範圍是1e5,雙層循環肯定會超時,那麼怎麼辦呢?我們來分析一下問題,題幹讓我們尋找的是滿足(s[i]-s[j-1])%k= =0的情況,上述算法之所以會超時,原因在於需要枚舉i,j的範圍,那麼我們是否換種思路。即求s[i]%k= =s[j-1]%k的情況有多少。因爲求s[i]%k= =s[j-1]%k的情況並不需要進行枚舉,只需把s[i]%=k儲存 桶排序 最後再加上這個數本身就是k的倍數的情況即可。

#include <stdio.h>
long long a[100005],s[100005],v[100005],n,k,ans,temp;      //滿足條件 (s[r]-s[l-1])%k==0 即(s[r]%k)==(s[i-1]%k) 則符合條件 
int main()
{
	scanf("%lld%lld",&n,&k);
	for(int i=0;i<n;i++)
	{
		scanf("%lld",&temp);
		s[i]=(s[i-1]+temp)%k;
		ans+=v[s[i]];
		v[s[i]]++;
	}
	ans+=v[0];
	printf("%lld",ans);
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章