【藍橋】算法能力恢復性練習1(進制、暴力、打表、素數、vector()、邏輯)

博客內容說明

本系列博客:《算法能力恢復性練習》,主要用於記錄個人備戰2020年藍橋杯,恢復算法能力與技巧的過程。

代碼和思路不一定正確(部分代碼和思路參考自他人)

歡迎大家交流學習,指正錯誤!

推薦練習網址:藍橋杯ACM訓練習題

1、類進制轉換題(去年省賽B題)

標題:年號字串(本題總分:5 分)
小明用字母 A 對應數字 1,B 對應 2,以此類推,用 Z 對應 26。對於 27
以上的數字,小明用兩位或更長位的字符串來對應,例如 AA 對應 27,AB 對
應 28,AZ 對應 52,LQ 對應 329。
請問 2019 對應的字符串是什麼?
【答案提交】
這是一道結果填空的題,你只需要算出結果後提交即可。本題的結果爲一
個大寫英文字符串,在提交答案時只填寫這個字符串,注意全部大寫,填寫多
餘的內容將無法得分。

分析
我自己之前分析過(其實我自己都不想看之前寫過的blogs):
【藍橋】第八屆C語言C組第7題 Excel地址(進制變形題,stack()簡單使用)
做了很多次了,但總覺得有什麼細節還沒理解到位,但無所謂了,我已經能做到“背”下答案了(就是標準進制轉換+一個特殊的技巧)

#include <iostream>
#include <stack>
using namespace std;
const int maxn=1e3+10;
typedef long long ll;
int main()
{
	int n=2019;
	stack<char> a;
	while(n){
		int r=n%26;
		if(r==0) r=26;//去掉這一行,這就是標準的進制轉換問題了 
		n=(n-r)/26;
		a.push(r+'A'-1); 
	}
	while(!a.empty()){
		printf("%c",a.top());
		a.pop();
	}
	return 0;
}

技巧
用Execl啊

2、簡單暴力題(去年省賽C題)

標題:數列求值 (本題總分:10 分)###
給定數列 1, 1, 1, 3, 5, 9, 17, …,從第 4 項開始,每項都是前 3 項的和。求
第 20190324 項的最後 4 位數字。
【答案提交】
這是一道結果填空的題,你只需要算出結果後提交即可。本題的結果爲一
個 4 位整數(提示:答案的千位不爲 0) ,在提交答案時只填寫這個整數,填寫
多餘的內容將無法得分。

代碼1:

#include <bits/stdc++.h>
using namespace std;
int main()
{
	int a=1,b=1,c=1,d;
	for(int i=4;i<=20190324;i++){
		d=(a+b+c)%10000;
		a=b,b=c,c=d;
	}
	cout<<d<<endl;
}

找了一下去年寫的

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <string>
using namespace std;
const int maxn=3e7;
int a[maxn];
int main()
{
	a[1]=a[2]=a[3]=1;
	for(int i=4;i<=20190324;i++)
	{
		a[i]=(a[i-1]%10000+a[i-2]%10000+a[i-3]%10000)%10000;
	}
	cout<<a[20190324]<<endl;	//4659
	return 0;
}

3、典型暴力題(去年省賽D題)

標題: 數的分解(本題總分:10 分)
【問題描述】
把 2019 分解成 3 個各不相同的正整數之和,並且要求每個正整數都不包
含數字 2 和 4,一共有多少種不同的分解方法?
注意交換 3 個整數的順序被視爲同一種方法,例如 1000+1001+18 和
1001+1000+18 被視爲同一種。
【答案提交】
這是一道結果填空的題,你只需要算出結果後提交即可。本題的結果爲一
個整數,在提交答案時只填寫這個整數,填寫多餘的內容將無法得分。
分析
也沒啥好說的,去年錯了來着,給人的教訓就是:簡單題一定要認真,難題要戰略性放棄,儘量保證簡單題的正確率!

#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
bool check[3000];
bool ok(int num)
{
	while(num)
	{
		int t=num%10;
		if(t==2||t==4)
			return false;
		num/=10;
	}
	return true;
}
int main()
{
	int n=2019;
	int cnt=0; 
	memset(check,0,sizeof(check));
	for(int i=1;i<2018/3+1;i++)
	{
		for(int j=i;i+j<2018;j++)
		{
			for(int k=j;i+j+k<=2019;k++)
			{
				if((i+j+k)==2019)
				{
					if(ok(i)&&ok(j)&&ok(k)&&(i!=j)&&(j!=k)&&(i!=k))
						cnt++;
				}
			}
		}
	}
	printf("%d\n",cnt); //40785
	return 0;
}

4、簡單動態規劃題

問題 1004: [遞歸]母牛的故事

時間限制: 1Sec 內存限制: 128MB 提交: 42366 解決: 12767

題目描述
有一頭母牛,它每年年初生一頭小母牛。每頭小母牛從第四個年頭開始,每年年初也生一頭小母牛。請編程實現在第n年的時候,共有多少頭母牛?

輸入
輸入數據由多個測試實例組成,每個測試實例佔一行,包括一個整數n(0<n<55),n的含義如題目中描述。
n=0表示輸入數據的結束,不做處理。

輸出
對於每個測試實例,輸出在第n年的時候母牛的數量。
每個輸出佔一行。

樣例輸入
2
4
5
0
樣例輸出
2
4
6

分析
很經典的一個入門題,基礎到我有點不確定這是不是動態規劃題了(當然,好久沒做題一上來也想了好一會兒)

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
typedef long long ll;
int main()
{
	ll n,a[60];
	for(int i=1; i<=4; i++) {
		a[i]=i;
	}
	for(int i=5; i<60; i++) {
		a[i]=a[i-1]+a[i-3];
	}
	while(cin>>n&&n) {
		if(n<=4)
			printf("%lld\n",n);
		else {
			printf("%lld\n",a[n]);
		}
	}
	return 0;
}

5、素數題

問題 1084: 用篩法求之N內的素數。

時間限制: 1Sec 內存限制: 64MB 提交: 9901 解決: 5911

題目描述
用篩法求之N內的素數。
輸入
N
輸出
0~N的素數
樣例輸入
10
樣例輸出
2
3
5
7

分析:
也沒設置什麼陷阱,就是單純怎麼輸出素數,怎麼來。

代碼1:
遍歷終止條件sqrt(n)最好,且注意排除2特殊情況

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
typedef long long ll;
bool isprime(ll n){
	if(n==2) return true;
	for(int i=2;i<=sqrt(n);i++){
		if(n%i==0)
			return false;
	}
	return true;
}
int main()
{
	ll n;
	cin>>n; 
	for(int i=2;i<=n;i++){
		if(isprime(i))
			cout<<i<<endl; 
	}
	return 0;
}

代碼2:
集思廣益

#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn = 1e6+10;
int prime[maxn];
bool number[maxn];
int n,cnt;
void isprime(int n){    
    memset(number, true, sizeof number);
    number[0]=number[1] = false;
    cnt = 0;
    for (int i = 2; i <= n; i++){
        if (number[i])
            prime[cnt++] = i;
        for (int j = 0; j < cnt&&prime[j] * i <= n; j++){
            number[prime[j] * i] = false;   //d=====( ̄▽ ̄*)b 
            if (i%prime[j] == 0)
                break;
        }
    }
}
int main()
{
    cin >> n;
    isprime(n);
    for (int i = 0; i < cnt; i++){
        cout << prime[i] << endl;
    }
	return 0;
}

6、數組和排序練習題

問題 1462: [藍橋杯][基礎練習VIP]Huffuman樹

時間限制: 1Sec 內存限制: 128MB 提交: 813 解決: 473

題目描述
Huffman樹在編碼中有着廣泛的應用。在這裏,我們只關心Huffman樹的構造過程。

給出一列數{pi}={p0, p1, …, pn-1},用這列數構造Huffman樹的過程如下:

  1. 找到{pi}中最小的兩個數,設爲pa和pb,將pa和pb從{pi}中刪除掉,然後將它們的和加入到{pi}中。這個過程的費用記爲pa + pb。

  2. 重複步驟1,直到{pi}中只剩下一個數。

在上面的操作過程中,把所有的費用相加,就得到了構造Huffman樹的總費用。

本題任務:對於給定的一個數列,現在請你求出用該數列構造Huffman樹的總費用。

例如,對於數列{pi}={5, 3, 8, 2, 9},Huffman樹的構造過程如下:

  1. 找到{5, 3, 8, 2, 9}中最小的兩個數,分別是2和3,從{pi}中刪除它們並將和5加入,得到{5, 8, 9, 5},費用爲5。

  2. 找到{5, 8, 9, 5}中最小的兩個數,分別是5和5,從{pi}中刪除它們並將和10加入,得到{8, 9, 10},費用爲10。

  3. 找到{8, 9, 10}中最小的兩個數,分別是8和9,從{pi}中刪除它們並將和17加入,得到{10, 17},費用爲17。

  4. 找到{10, 17}中最小的兩個數,分別是10和17,從{pi}中刪除它們並將和27加入,得到{27},費用爲27。

  5. 現在,數列中只剩下一個數27,構造過程結束,總費用爲5+10+17+27=59。
    輸入
    輸入的第一行包含一個正整數n(n< =100)。

接下來是n個正整數,表示p0, p1, …, pn-1,每個數不超過1000。
輸出
輸出用這些數構造Huffman樹的總費用。
樣例輸入
5

5 3 8 2 9
樣例輸出
59

分析
練習了一下vector()
寫完感覺用priority_queue()也挺好

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn=1e3+10;
typedef long long ll;
int main()
{
	vector<int> a;
	int n,tmp,sum=0;
	scanf("%d",&n);
	for(int i=0; i<n; i++) {
		scanf("%d",&tmp);
		a.push_back(tmp);
	}
	sort(a.begin(),a.end());
	while((n--)>1) {
		a[1]=a[0]+a[1];
		sum+=a[1];
		a.erase(a.begin());
		sort(a.begin(),a.end());
	}
	printf("%d",sum);
	return 0;
}

7、基礎邏輯題

問題 1498: [藍橋杯][算法提高VIP]兇手

時間限制: 1Sec 內存限制: 128MB 提交: 183 解決: 92

題目描述
巴斯維克命案抓住了六個嫌疑犯,他們的口供如下:
A:我不是罪犯
B:A、C中有一個是罪犯
C:A和B說了假話
D:C和F說了假話
E:其他五個人中,只有A和D說了真話
F:我是罪犯
他們中只有一半說了真話,兇手只有一個。
本題可能有多種可能性,即正確答案(找到唯一的兇手)可能有多個,但每一個可能的答案(某一個是兇手)都滿足上述口供。
請編程找出可能的兇手輸出。
(假設唯一的兇手是A或者D或者E,則輸出結果爲三行,按字母順序依次輸出)
輸入

輸出

樣例輸入

樣例輸出
A
D
E

分析:
單靠邏輯硬推不是不可以,就是有點不保險~~~

#include<iostream>
#include<cstring>
int suspects[6]; 
int f1()	//A:我不是罪犯 
{
	if(!suspects[0])
		return 1;
	return 0;
}
int f2()	//B:A、C中有一個是罪犯 
{
	if(suspects[0]||suspects[2])
		return 1;
	return 0;
}
int f3()	//C:A和B說了假話
{
	if(!f1()&&!f2())
		return 1;
	return 0;
}
int f6(){	//F:我是罪犯 
	if(suspects[5]==1)
		return 1;
	return 0;
}
int f4() 	//C和F說了假話  
{
	if(!f3()&&!f6())
		return 1;
	return 0;
}
int f5()   //其他五個人中,只有A和D說了真話  
{
	if(f1()&&f4()&&!f2()&&!f3()&&!f6())
		return 1;
	return 0;
}

int main()
{
	for(int i=0;i<6;i++){
		memset(suspects,0,sizeof(suspects));
		suspects[i]=1;
		if(f1()+f2()+f3()+f4()+f5()+f6()==3)
			printf("%c\n",'A'+i);
	}
	return 0;
}

後記

今年原計劃4月19日的藍橋杯省賽最終還是因爲衆所周知的原因推遲了,具體哪一天舉行還不得而知,畢竟大學生們什麼時候開學還不知道呢。

“最開始,我們熱烈討論着開學應該會推遲幾天;之後,有些人隱隱約約透露出前四周不開學的消息;再後來,我們都猛然意識到清明也要在家裏過了;最近,偶爾能看到有人邊發着😂,邊吐槽大家五一後再見了…”

一點點複習吧~~~

近期事多且雜,考研正在成爲生活重心,博客質量“隨心情”

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