第九屆藍橋杯 b組 解析

標題:第幾天

2000年的1月1日,是那一年的第1天。
那麼,2000年的5月4日,是那一年的第幾天?

注意:需要提交的是一個整數,不要填寫任何多餘內容。

解題思路:最簡單的做法就是直接點桌面右下角的日期,選回2000年自己一個一個加月份去吧。還有一種做法就是數手指判斷月份的天數(記得判斷一下是否閏年哦)

答案:125
————————————————

標題:明碼

漢字的字形存在於字庫中,即便在今天,16點陣的字庫也仍然使用廣泛。
16點陣的字庫把每個漢字看成是16x16個像素信息。並把這些信息記錄在字節中。

一個字節可以存儲8位信息,用32個字節就可以存一個漢字的字形了。
把每個字節轉爲2進製表示,1表示墨跡,0表示底色。每行2個字節,
一共16行,佈局是:

第1字節,第2字節
第3字節,第4字節
....
第31字節, 第32字節

這道題目是給你一段多個漢字組成的信息,每個漢字用32個字節表示,這裏給出了字節作爲有符號整數的值。

題目的要求隱藏在這些信息中。你的任務是復原這些漢字的字形,從中看出題目的要求,並根據要求填寫答案。

這段信息是(一共10個漢字):
4 0 4 0 4 0 4 32 -1 -16 4 32 4 32 4 32 4 32 4 32 8 32 8 32 16 34 16 34 32 30 -64 0
16 64 16 64 34 68 127 126 66 -124 67 4 66 4 66 -124 126 100 66 36 66 4 66 4 66 4 126 4 66 40 0 16
4 0 4 0 4 0 4 32 -1 -16 4 32 4 32 4 32 4 32 4 32 8 32 8 32 16 34 16 34 32 30 -64 0
0 -128 64 -128 48 -128 17 8 1 -4 2 8 8 80 16 64 32 64 -32 64 32 -96 32 -96 33 16 34 8 36 14 40 4
4 0 3 0 1 0 0 4 -1 -2 4 0 4 16 7 -8 4 16 4 16 4 16 8 16 8 16 16 16 32 -96 64 64
16 64 20 72 62 -4 73 32 5 16 1 0 63 -8 1 0 -1 -2 0 64 0 80 63 -8 8 64 4 64 1 64 0 -128
0 16 63 -8 1 0 1 0 1 0 1 4 -1 -2 1 0 1 0 1 0 1 0 1 0 1 0 1 0 5 0 2 0
2 0 2 0 7 -16 8 32 24 64 37 -128 2 -128 12 -128 113 -4 2 8 12 16 18 32 33 -64 1 0 14 0 112 0
1 0 1 0 1 0 9 32 9 16 17 12 17 4 33 16 65 16 1 32 1 64 0 -128 1 0 2 0 12 0 112 0
0 0 0 0 7 -16 24 24 48 12 56 12 0 56 0 -32 0 -64 0 -128 0 0 0 0 1 -128 3 -64 1 -128 0 0

注意:需要提交的是一個整數,不要填寫任何多餘內容。

思路:本題我寫過題解,第九屆藍橋杯 b組 明碼,本題並不難,只是將10進制數轉換爲2進制,唯一需要注意的是負數轉變爲二進制的情況,需要注意原碼,補碼,反碼,不瞭解的點這裏

#include <stdio.h>
#include <stdlib.h>  // 387420489
#include <string.h>
int a[8],k,l;
void er(int x)
{ 
	l=0;
	memset(a,0,sizeof(a));
	if(x>=0)
	{
		while(x)
		{
			int t=x%2;
			a[l++]=t;
			x/=2;
		}
	}
	else
	{
		x*=-1;
		while(x)
		{
			int t=x%2;
			a[l++]=t;
			x/=2;
		}
		for(int i=0;i<8;i++)
		{
			if(a[i])	a[i]=0;
			else a[i]=1;
		}
		a[0]+=1;
		int i=0;
			while(a[i]==2)
			{
				a[i]=0;
				a[i+1]++;
				i++;
			}
	}
	for(int i=7;i>=0;i--)
		printf("%d",a[i]);
}
int main()
{
	int t1,t2;
	for(int i=0;i<160;i++)
	{
		scanf("%d%d",&t1,&t2);
		er(t1);
		er(t2);
		printf("\n");
	}
	return 0;
}

標題:乘積尾零

如下的10行數據,每行有10個整數,請你求出它們的乘積的末尾有多少個零?

5650 4542 3554 473 946 4114 3871 9073 90 4329
2758 7949 6113 5659 5245 7432 3051 4434 6704 3594
9937 1173 6866 3397 4759 7557 3070 2287 1453 9899
1486 5722 3135 1170 4014 5510 5120 729 2880 9019
2049 698 4582 4346 4427 646 9742 7340 1230 7683
5693 7015 6887 7381 4172 4341 2909 2027 7355 5649
6701 6645 1671 5978 2704 9926 295 3125 3878 6785
2066 4247 4800 1578 6652 4616 1113 6205 3264 2915
3966 5291 2904 1285 2193 1428 2265 8730 9436 7074
689 5510 8243 6114 337 4096 8199 7313 3685 211

注意:需要提交的是一個整數,表示末尾零的個數。不要填寫任何多餘內容
————————————————

思路:兩數相乘,末尾有多少個零,怎麼計算呢?我們只需要計算這些數裏有多少對2,5。有多少對,就有多少個零,想到這裏,這道題就解決了。下面是一道類似的變形題 冷門進制

#include <stdio.h>  // 31
int t,t1,t2,ans;
int min(int x,int y)
{
	return x<y?x:y;
}
int main()
{
	for(int i=0;i<100;i++)
	{
		scanf("%d",&t);
		if(t%2==0)
		{
			int temp1=t;
			while(temp1%2==0)
			{
				t1++;
				temp1/=2;
			}
		}
		if(t%5==0)
		{
			int temp2=t;
			while(temp2%5==0)
			{
				t2++;
				temp2/=5;
			}
		}
	}
	ans=min(t1,t2);
	printf("%d",ans);
	return 0;
}

標題:測試次數

x星球的居民脾氣不太好,但好在他們生氣的時候唯一的異常舉動是:摔手機。
各大廠商也就紛紛推出各種耐摔型手機。x星球的質監局規定了手機必須經過耐摔測試,並且評定出一個耐摔指數來,之後才允許上市流通。

x星球有很多高聳入雲的高塔,剛好可以用來做耐摔測試。塔的每一層高度都是一樣的,與地球上稍有不同的是,他們的第一層不是地面,而是相當於我們的2樓。

如果手機從第7層扔下去沒摔壞,但第8層摔壞了,則手機耐摔指數=7。
特別地,如果手機從第1層扔下去就壞了,則耐摔指數=0。
如果到了塔的最高層第n層扔沒摔壞,則耐摔指數=n

爲了減少測試次數,從每個廠家抽樣3部手機參加測試。

某次測試的塔高爲1000層,如果我們總是採用最佳策略,在最壞的運氣下最多需要測試多少次才能確定手機的耐摔指數呢?

請填寫這個最多測試次數。

注意:需要填寫的是一個整數,不要填寫任何多餘內容。
————————————————
思路:這個題非常好。。。源自於一道很經典的谷歌面試題,我之前寫過這道題的思路和代碼,點這裏-----------------二分是找不到正確答案的。本題需要動態規劃的思想 。首先,假設我們有N部手機,M層樓。那麼題意要求我們在剛好摔壞N部手機時恰好測試出手機的抗摔係數,(採用最優策略)即此時我們測試次數的最小值是多少。注意,這裏的意思是,因爲我們選擇測試樓層的策略的原因,在N部手機M層樓的情況下,測試任何抗摔係數的手機的次數都不大於我們所求的次數。這裏,我們採用動態規劃的做法。顯然,如果我們只有一部手機,那麼無論如何,我們都老老實實的要從第一層開始向上摔,即dp[1][j]=j. 當我們手中的手機數量大於1的時候,我們便可以考慮開始在不同的樓層測試抗摔係數。我們假設答案爲k次,那麼顯然,第一次的時候我們需要站在第k層樓摔。假如此時我們手裏的手機摔壞了,那麼我們還剩下n-1部手機,測試k-1層樓;假如我們沒有摔壞,那麼我們還有n部手機,測試j-k層樓。
代碼:

#include <stdio.h>
int dp[5][1005],k;  
//我們假設第一次站在k層樓摔 
//dp[i][j]代表有i部手機j層樓時摔壞所有手機的情況下 測試任意抗摔係數的最多次數 
//dp[i][j]=min(dp[i][j],max(dp[i-1][k-1],dp[i][j-k)); 
//狀態轉移方程表示 :1.不同k之間取最小值 2.同一 k之間的不同情況取最大值,避免遺漏(如果在這裏取了最小值,那麼意味着需要更多測試次數情況的測試不到) 
//dp[i][j-k]表示還剩下j-k層樓沒有測試,在這裏不要想當然的認爲樓層越高越容易摔碎,我們需要的只是能測試所有的樓層即可 
int min(int x,int y)
{
	return x<y?x:y;
}
int max(int x,int y)
{
	return x>y?x:y;
}
int main()
{
	for(int i=1;i<=3;i++)
	{
		for(int j=1;j<=1000;j++)
		{
			dp[i][j]=j;   //初始化 
		}
	 } 
	 for(int i=2;i<=3;i++)
	 {
	 	for(int j=2;j<=1000;j++)
	 	{
	 		for(int k=1;k<=j;k++)
	 		{
	 			dp[i][j]=min(dp[i][j],max(dp[i-1][k-1],dp[i][j-k])+1);
			 }
		 }
	 }
	 printf("%d",dp[3][1000]);
	return 0;
 } 


標題:快速排序。

以下代碼可以從數組a[]中找出第k小的元素。

它使用了類似快速排序中的分治算法,期望時間複雜度是O(N)的。

請仔細閱讀分析源碼,填寫劃線部分缺失的內容。

#include <stdio.h>

int quick_select(int a[], int l, int r, int k) {
int p = rand() % (r - l + 1) + l;
int x = a[p];
{int t = a[p]; a[p] = a[r]; a[r] = t;}
int i = l, j = r;
while(i < j) {
while(i < j && a[i] < x) i++;
if(i < j) {
a[j] = a[i];
j–;
}
while(i < j && a[j] > x) j–;
if(i < j) {
a[i] = a[j];
i++;
}
}
a[i] = x;
p = i;
if(i - l + 1 == k) return a[i];
if(i - l + 1 < k) return quick_select( _____________________________ ); //填空
else return quick_select(a, l, i - 1, k);
}

int main()
{
int a[] = {1, 4, 2, 8, 5, 7, 23, 58, 16, 27, 55, 13, 26, 24, 12};
printf("%d\n", quick_select(a, 0, 14, 5));
return 0;
}

注意:只填寫劃線部分缺少的代碼,不要抄寫已經存在的代碼或符號

答案:(a, i+1, r, k - (i - l + 1));

思路:這是一道代碼填空題,相信接觸過快速排序的同學應該知道答案是怎麼來的。不瞭解快速排序的點這裏。第1~3個參數比較容易想到,但第4個空怎麼來的呢,我們可以看橫線前的條件if(i - l + 1 == k),由於參數 l 是會變化的,所以保持選第k小不變,k也要變化,減去i - l + 1就可以啦。---------------聽說藍橋杯取消代碼填空題了哈哈哈

標題:遞增三元組

給定三個整數數組
A = [A1, A2, … AN],
B = [B1, B2, … BN],
C = [C1, C2, … CN],
請你統計有多少個三元組(i, j, k) 滿足:

  1. 1 <= i, j, k <= N
  2. Ai < Bj < Ck

【輸入格式】
第一行包含一個整數N。
第二行包含N個整數A1, A2, … AN。
第三行包含N個整數B1, B2, … BN。
第四行包含N個整數C1, C2, … CN。

對於30%的數據,1 <= N <= 100
對於60%的數據,1 <= N <= 1000
對於100%的數據,1 <= N <= 100000 0 <= Ai, Bi, Ci <= 100000

【輸出格式】
一個整數表示答案

【樣例輸入】
3
1 1 1
2 2 2
3 3 3

【樣例輸出】
27

資源約定:
峯值內存消耗(含虛擬機) < 256M
CPU消耗 < 1000ms
————————————————
思路:二分查找。如果我們以a數組爲基準的話,那麼我們需要去遍歷b數組,這樣時間複雜度會很高。那麼我們是不是可以換種思路,即以b數組爲基準,然後在a數組裏找到小於b[i]的最大的數,在c數組裏找到大於b[i]的最小的數,然後將元素數量相乘,便可以得到答案。

#include <stdio.h>
#include <stdlib.h>
long long n,a[100005],b[100005],c[100005];
long long ans;
int kk(const void *p,const void *q)
{
	return *(int *)p-*(int *)q;
}
long long er1(long long x)      //返回有幾個比x小的元素
{
	long long  head=0;
	long long  tail=n;
	long long  mid=(head+tail)>>1;
	while(tail>head)
	{
		if(a[mid]<x)
		{
			head=mid+1;
		}
		else if(a[mid]>=x)
		{
			tail=mid;
		}
		mid=(head+tail)>>1;
	}
	return head;
}
int er2(int x)  //返回有幾個不大於x的元素
{
	long long  head=0;
	long long  tail=n;
	long long  mid=(head+tail)>>1;
	while(tail>head)
	{
		if(c[mid]>x)
		{
			tail=mid;
		}
		else if(c[mid]<=x)
		{
			head=mid+1;
		}
		mid=(head+tail)>>1;
	}
	return head;
}
int main()
{
	scanf("%lld",&n);
	for(int i=0;i<n;i++)
	{
		scanf("%d",&a[i]);
	}
	for(int i=0;i<n;i++)
	{
		scanf("%lld",&b[i]);
	}
	for(int i=0;i<n;i++)
	{
		scanf("%lld",&c[i]);
	}
	qsort(a,n,sizeof(long long ),kk);
	qsort(b,n,sizeof(long long),kk);
	qsort(c,n,sizeof(long long ),kk);
	for(int i=0;i<n;i++)
	{
		ans+=er1(b[i])*(n-er2(b[i]));
	}
	printf("%lld",ans); 
	return 0;
}

標題:螺旋折線

在這裏插入圖片描述
如圖p1.png所示的螺旋折線經過平面上所有整點恰好一次。
對於整點(X, Y),我們定義它到原點的距離dis(X, Y)是從原點到(X, Y)的螺旋折線段的長度。

例如dis(0, 1)=3, dis(-2, -1)=9

給出整點座標(X, Y),你能計算出dis(X, Y)嗎?

【輸入格式】
X和Y

對於40%的數據,-1000 <= X, Y <= 1000
對於70%的數據,-100000 <= X, Y <= 100000
對於100%的數據, -1000000000 <= X, Y <= 1000000000

【輸出格式】
輸出dis(X, Y)

【樣例輸入】
0 1

【樣例輸出】
3

資源約定:
峯值內存消耗(含虛擬機) < 256M
CPU消耗 < 1000ms

思路:看一眼這道題的數據範圍,感覺模擬着做肯定會超時,所以我們先找一下這個圖的規律。在這裏插入圖片描述畫工有限,相信聰明的你一定能看懂我的意思的。即:我們把圖變爲若干個正方形,很容易發現,前n個正方形的長度滿足一定的規律,我們只要找出這個點屬於第幾個正方形,然後把長度加起來即可,下面是我找到的規律。在這裏插入圖片描述在這裏插入圖片描述下面是代碼:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
long long x,y,ans,n;
long long max(long long a,long long b)
{
	return a>b?a:b;
}
int main()
{
	scanf("%lld%lld",&x,&y);
	if(x<0)
	{
		if(x==y)
		{
			n=abs(x);
			ans=(8*(n+1)*n)/2;
		}
		else 
		{
			n=max(abs(x),abs(y));
			if(y<-n+1)
			{
				ans=abs(x)+6.5*n+(8*(n-1)*n)/2;
			}
			else
			{
				ans=abs(y+n)+n+x+(8*(n-1)*n)/2;
			}
		}
		
	 } 
	 else if(!x)
	 {
	 	n=abs(y);
	 	if(y>0)
	 	{
	 		ans=3*n+(8*(n-1)*n)/2;
		 }
		 else if(y<0)
		 {
		 	ans=7*n+(8*(n-1)*n)/2;
		 }
		 else
		 {
		 	ans=0;
		 }
	 }
	 else if(x>0)
	 {
	 	n=max(abs(x),abs(y));
	 	if(y>0)
	 	{
	 		ans=3*n+x+n-y+(8*(n-1)*n)/2;
		 }
		 else if(y<0)
		 {
		 	ans=5*n+abs(y)+(n-abs(x))+(8*(n-1)*n)/2;
		 }
		 else
		 {
		 	ans=5*n+(8*(n-1)*n)/2;
		 }
	 }
	 printf("%lld",ans);
	return 0;
}

標題:日誌統計

小明維護着一個程序員論壇。現在他收集了一份"點贊"日誌,日誌共有N行。其中每一行的格式是:

ts id

表示在ts時刻編號id的帖子收到一個"贊"。

現在小明想統計有哪些帖子曾經是"熱帖"。如果一個帖子曾在任意一個長度爲D的時間段內收到不少於K個贊,小明就認爲這個帖子曾是"熱帖"。

具體來說,如果存在某個時刻T滿足該帖在[T, T+D)這段時間內(注意是左閉右開區間)收到不少於K個贊,該帖就曾是"熱帖"。

給定日誌,請你幫助小明統計出所有曾是"熱帖"的帖子編號。

【輸入格式】
第一行包含三個整數N、D和K。
以下N行每行一條日誌,包含兩個整數ts和id。

對於50%的數據,1 <= K <= N <= 1000
對於100%的數據,1 <= K <= N <= 100000 0 <= ts <= 100000 0 <= id <= 100000

【輸出格式】
按從小到大的順序輸出熱帖id。每個id一行。

【輸入樣例】
7 10 2
0 1
0 10
10 10
10 1
9 1
100 3
100 3

【輸出樣例】
1
3
————————————————
思路:尺取法。不瞭解尺取法的點這裏,用c語言寫了一份代碼,內存是超限的,c語言中沒有容器這個東西。。

標題:全球變暖

你有一張某海域NxN像素的照片,".“表示海洋、”#"表示陸地,如下所示:


.##…
.##…
…##.
…####.
…###.

其中"上下左右"四個方向上連在一起的一片陸地組成一座島嶼。例如上圖就有2座島嶼。

由於全球變暖導致了海面上升,科學家預測未來幾十年,島嶼邊緣一個像素的範圍會被海水淹沒。具體來說如果一塊陸地像素與海洋相鄰(上下左右四個相鄰像素中有海洋),它就會被淹沒。

例如上圖中的海域未來會變成如下樣子:





…#…

請你計算:依照科學家的預測,照片中有多少島嶼會被完全淹沒。

【輸入格式】
第一行包含一個整數N。 (1 <= N <= 1000)
以下N行N列代表一張海域照片。

照片保證第1行、第1列、第N行、第N列的像素都是海洋。

【輸出格式】
一個整數表示答案。

【輸入樣例】
7

.##…
.##…
…##.
…####.
…###.

【輸出樣例】
1

思路:這題比較簡單,搜索做就好了,我用的dfs,bfs應該也能做。首先我們找出所有島嶼並對他們進行編號並記錄下島嶼數量的最大值,然後我們淹沒所有符合條件的島嶼,最後看一下剩下幾個島嶼,用最大值減去這個數就好了。

#include <stdio.h>
int n,b[1005][1005],dd=0,vv[1000005],ans,Max=-1;
int next[4][2]={0,1,1,0,0,-1,-1,0};
char a[1005][1005];
int max(int x,int y)
{
    return x>y?x:y;
}
void ok(int x,int y) //是否可以被淹沒
{
    for(int i=0;i<4;i++)
    {
        int tx=x+next[i][0];
        int ty=y+next[i][1];
        if(a[tx][ty]=='.'&&tx>=0&&tx<n&&ty>=0&&ty<n)
        {
            b[x][y]=0;
            return ;
        }
    }
}
void dfs(int x,int y,int gg)
{
    int tx;
    int ty;
    for(int i=0;i<4;i++)
    {
        tx=x+next[i][0];
        ty=y+next[i][1];
        if(!b[tx][ty]&&a[tx][ty]=='#'&&tx>=0&&tx<n&&ty>=0&&ty<n)  //沒被標記過的陸地·
        {
            b[tx][ty]=gg;
            dfs(tx,ty,gg);
        }
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%s",a[i]);
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(!b[i][j]&&a[i][j]=='#')   //沒被標記過的陸地
            {
                b[i][j]=++dd;
                dfs(i,j,dd);              //標記相連的所有陸地
                Max=max(dd,Max);
            }
        }
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(a[i][j]=='#')
            {
                ok(i,j);   //淹沒陸地
            }
        }
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(b[i][j]&&!vv[b[i][j]])  //沒被淹沒並且該島沒有記錄過
            {
                vv[b[i][j]]=1;
                ans++;
            }
        }
    }
    printf("%d",Max-ans);
    return 0;
}

·································································································
·································································································
第十題我不會,如果有願意教我的可以加我主頁qq。個人感覺,第九屆比第十屆要難一些。
上面代碼 或者 思路有問題的話,歡迎指正 。

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