博客內容說明
本系列博客:《算法能力恢復性練習》,主要用於記錄個人備戰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樹的過程如下:
-
找到{pi}中最小的兩個數,設爲pa和pb,將pa和pb從{pi}中刪除掉,然後將它們的和加入到{pi}中。這個過程的費用記爲pa + pb。
-
重複步驟1,直到{pi}中只剩下一個數。
在上面的操作過程中,把所有的費用相加,就得到了構造Huffman樹的總費用。
本題任務:對於給定的一個數列,現在請你求出用該數列構造Huffman樹的總費用。
例如,對於數列{pi}={5, 3, 8, 2, 9},Huffman樹的構造過程如下:
-
找到{5, 3, 8, 2, 9}中最小的兩個數,分別是2和3,從{pi}中刪除它們並將和5加入,得到{5, 8, 9, 5},費用爲5。
-
找到{5, 8, 9, 5}中最小的兩個數,分別是5和5,從{pi}中刪除它們並將和10加入,得到{8, 9, 10},費用爲10。
-
找到{8, 9, 10}中最小的兩個數,分別是8和9,從{pi}中刪除它們並將和17加入,得到{10, 17},費用爲17。
-
找到{10, 17}中最小的兩個數,分別是10和17,從{pi}中刪除它們並將和27加入,得到{27},費用爲27。
-
現在,數列中只剩下一個數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日的藍橋杯省賽最終還是因爲衆所周知的原因推遲了,具體哪一天舉行還不得而知,畢竟大學生們什麼時候開學還不知道呢。
“最開始,我們熱烈討論着開學應該會推遲幾天;之後,有些人隱隱約約透露出前四周不開學的消息;再後來,我們都猛然意識到清明也要在家裏過了;最近,偶爾能看到有人邊發着😂,邊吐槽大家五一後再見了…”
一點點複習吧~~~
近期事多且雜,考研正在成爲生活重心,博客質量“隨心情”