2020藍橋杯省賽B組C++(第二場)真題
心得體會
前面總結了很多歷屆的省賽真題,這次終於輪到自己上戰場上體驗真題啦~為此次藍橋杯省賽也是準備了一兩週時間,聽說比較水,題不是很難,會暴力就能拿獎哈哈哈考完確實有點這樣的感覺,但是能把五個填空題萬無一失的做全對也不是一件簡單的事情。先說說自己吧,一週後成績出來還算滿意,在遼寧省排名靠前(省一,拿到國賽資格啦),填空題只做對了前三道…其實挺氣的,剛考完看答案心態沒了,第四個填空題算到10月1日,我不小心算到考試當天10月17日了hhh第五題我是暴力數的,少算了兩種情況,可能是大題寫得還行,初略看了下前三個大題基本滿分,第四個…能力有限,第五個暴力寫了一半,估計能得到一些分。其實總體感覺也一般吧,並沒有達到自己的預期發揮。不多想了,好好放寬心態,準備一下11月14日國賽!
準備了啥?
很多人都說藍橋杯…暴力杯,嗯嗯沒錯大概就是這樣,啊哈哈哈其實就花了幾天時間準備準備就考了,有點別的事情在忙。也就是做了近五年的真題,總結了一下演算法和經常考到的題型等等。想要寫的輕鬆些當然用演算法實現肯定是更好了。
總結需要掌握的基礎演算法:排序、雜湊、遞迴、貪心、二分、雙指標、數學問題還有C++ STL標準模板庫等等
進階的資料結構:棧、佇列、連結串列、深度優先搜尋(DFS)、廣度優先搜尋(BFS)、樹、圖、並查集還有動態規劃等等
試題A 門牌製作(5分)
【問題描述】
小藍要為一條街的住戶製作門牌號。
這條街一共有 2020 位住戶,門牌號從 1 到 2020 編號。
小藍製作門牌的方法是先製作 0 到 9 這幾個數字字元,最後根據需要將字
符貼上到門牌上,例如門牌 1017 需要依次貼上字元 1、 0、 1、 7,即需要 1 個
字元 0, 2 個字元 1, 1 個字元 7。
請問要製作所有的 1 到 2020 號門牌,總共需要多少個字元 2?
【答案提交】
這是一道結果填空的題,你只需要算出結果後提交即可。本題的結果為一個整數,在提交答案時只填寫這個整數,填寫多餘的內容將無法得分。
答案:624
試題B 既約分數(5分)
【問題描述】
如果一個分數的分子和分母的最大公約數是1,這個分數稱為既約分數。例如,3/4 , 5/2 , 1/8 , 7/1都是既約分數。請問,有多少個既約分數,分子和分母都是1 到2020 之間的整數(包括1和2020)?
【答案提交】
這是一道結果填空的題,你只需要算出結果後提交即可。本題的結果為一個整數,在提交答案時只填寫這個整數,填寫多餘的內容將無法得分。
答案:2481215
試題C 蛇形填數(10分)
【問題描述】
如下圖所示,小明用從1 開始的正整數“蛇形”填充無限大的矩陣。
容易看出矩陣第二行第二列中的數是5。請你計算矩陣中第20 行第20 列的數是多少?
【答案提交】
這是一道結果填空的題,你只需要算出結果後提交即可。本題的結果為一
個整數,在提交答案時只填寫這個整數,填寫多餘的內容將無法得分。
答案:761
#include <stdio.h>
int a[100][100];
int cnt=1;
int main()
{
int i;
int x,y;
for(i = 1 ; i <= 40; i++)
{
if(i % 2==1 )
{
for(x = i, y = 1; x >= 1 && y <= i; x--, y++)
a[x][y] = cnt++;
}
else
{
for(int x = 1, y = i; x <= i && y >= 1; x++, y--)
a[x][y] = cnt++;
}
}
printf("%d\n", a[20][20]);
return 0;
}
試題D 跑步鍛鍊(10分)
【問題描述】
小藍每天都鍛鍊身體。
正常情況下,小藍每天跑 1 千米。如果某天是週一或者月初(1 日),為了
激勵自己,小藍要跑 2 千米。如果同時是週一或月初,小藍也是跑 2 千米。
小藍跑步已經堅持了很長時間,從 2000 年 1 月 1 日週六(含)到 2020 年
10 月 1 日週四(含)。請問這段時間小藍總共跑步多少千米?
【答案提交】
這是一道結果填空的題,你只需要算出結果後提交即可。本題的結果為一
個整數,在提交答案時只填寫這個整數,填寫多餘的內容將無法得分。
答案:8879
試題E 七段碼(15分)
【問題描述】
小藍要用七段碼數碼管來表示一種特殊的文字。
七段碼上圖給出了七段碼數碼管的一個圖示,數碼管中一共有7 段可以發光的二極體,分別標記為a, b, c, d, e, f, g。小藍要選擇一部分二極體(至少要有一個)發光來表達字元。在設計字元的表達時,要求所有發光的二極體是連成一片的。
例如:b 發光,其他二極體不發光可以用來表達一種字元。
例如:c 發光,其他二極體不發光可以用來表達一種字元。這種方案與上一行的方案可以用來表示不同的字元,儘管看上去比較相似。
例如:a, b, c, d, e 發光,f, g 不發光可以用來表達一種字元。
例如:b, f 發光,其他二極體不發光則不能用來表達一種字元,因為發光的二極體沒有連成一片。
請問,小藍可以用七段碼數碼管表達多少種不同的字元?
####【答案提交】
這是一道結果填空的題,你只需要算出結果後提交即可。本題的結果為一
個整數,在提交答案時只填寫這個整數,填寫多餘的內容將無法得分。
答案:80
//a-0,b-1,c-2,d-3,e-4,f-5,g-6
#include<iostream>
#include<cstring>
#include<set>
using namespace std;
int ve[7][7];
bool visit[7];
int ans=0;
set<set<int> > se;
void dfs(int x,set<int> s)
{
if(!se.count(s))
{
se.insert(s);
ans++;
}
if(s.size()==7)
return ;
for(int j=0;j<7;j++)
{
if(visit[j]||!ve[x][j])
continue;
s.insert(j);
visit[j]=1;
dfs(j,s);
visit[j]=0;
s.erase(j);
}
}
void add(int x,int y)
{
ve[x][y]=1;
ve[y][x]=1;
}
int main()
{
//a的所有邊
add(0,1);
add(0,5);
//b的所有邊
add(1,6);
add(1,2);
//c的所有邊
add(2,6);
add(2,3);
//d的所有邊
add(3,4);
//e的所有邊
add(4,5);
add(4,6);
//f的所有邊
add(5,6);
set<int> s;
for(int i=0;i<=6;i++)
{
s.insert(i);
visit[i]=1;
dfs(i,s);
visit[i]=0;
s.erase(i);
}
cout<<ans<<endl;
}
程式設計題
試題F 成績統計(15分)
【問題描述】
小藍給學生們組織了一場考試,卷面總分為 100 分,每個學生的得分都是
一個 0 到 100 的整數。
如果得分至少是 60 分,則稱為及格。如果得分至少為 85 分,則稱為優秀。
請計算及格率和優秀率,用百分數表示,百分號前的部分四捨五入保留整
數。
【輸入格式】
輸入的第一行包含一個整數 n,表示考試人數。
接下來 n 行,每行包含一個 0 至 100 的整數,表示一個學生的得分。
【輸出格式】
輸出兩行,每行一個百分數,分別表示及格率和優秀率。百分號前的部分
四捨五入保留整數。
【樣例輸入】
7
80
92
56
74
88
100
【樣例輸出】
71%
43%
【評測用例規模與約定】
對於50% 的評測用例, 1 ≤ n ≤ 100。
對於所有評測用例,1 ≤ n ≤10000。
#include<stdio.h>
int main()
{
double a1=0,a2=0;
int n,i;
scanf("%d",&n);
for(i=0;i<n;i++){
int s;
scanf("%d",&s);
if(s>=60) a1++;
if(s>=85) a2++;
}
a1=(a1/n+0.005)*100;
a2=(a2/n+0.005)*100;
printf("%d%%\n%d%%",(int)a1,(int)a2);
return 0;
}
試題G 迴文日期(20分)
【問題描述】
2020 年春節期間,有一個特殊的日期引起了大家的注意:2020年2月2日。因為如果將這個日期按“yyyymmdd” 的格式寫成一個8 位數是20200202,
恰好是一個迴文數。我們稱這樣的日期是迴文日期。
有人表示20200202 是“千年一遇” 的特殊日子。對此小明很不認同,因為不到2年之後就是下一個迴文日期:20211202 即2021年12月2日。
也有人表示20200202 並不僅僅是一個迴文日期,還是一個ABABBABA型的迴文日期。對此小明也不認同,因為大約100 年後就能遇到下一個ABABBABA 型的迴文日期:21211212 即2121 年12 月12 日。算不上“千年一遇”,頂多算“千年兩遇”。
給定一個8 位數的日期,請你計算該日期之後下一個迴文日期和下一個ABABBABA型的迴文日期各是哪一天。
【輸入格式】
輸入包含一個八位整數N,表示日期。
【輸出格式】
輸出兩行,每行1 個八位數。第一行表示下一個迴文日期,第二行表示下
一個ABABBABA 型的迴文日期。
【樣例輸入】
20200202
【樣例輸出】
20211202
21211212
【評測用例規模與約定】
對於所有評測用例,10000101 ≤ N ≤ 89991231,保證N 是一個合法日期的8位數表示。
#include <iostream>
#include <iomanip>
using namespace std;
int a[12]={31,28,31,30,31,30,31,31,30,31,30,31};
bool isok(int x)//判斷閏年
{
if( x%400==0 ) return true;
if( x%100==0 ) return false;
if( x%4==0 ) return true;
return false;
}
int main()
{
int x;
cin >> x;
int year=x/10000;//輸入的年
int month=x%10000/100;//輸入的月
int day=x%100;//輸入的日
int flag=0;
int m=year%10*10+year%100/10;//年份對應的迴文月
int n=year/100%10*10+year/1000;//年份對應的迴文日
if(isok(year)) a[1]=29;
else a[1]=28;
if((m>month&&m<13)||(m==month&&n>day&&n<=a[m-1])){//當年對應的迴文日期在輸入的日期之後
cout<<setw(2)<<setfill('0')<<year<<setw(2)<<setfill('0')<<m<<setw(2)<<setfill('0')<<n<<endl;//輸出當年對應的迴文日期
flag=1;
if((year/1000!=year%10)&&(year%100==m%10*10+m/10)&&(m==n)){ //判斷當年對應的迴文日期是否是ABAB BABA型日期
cout<<setw(2)<<setfill('0')<<year<<setw(2)<<setfill('0')<<m<<setw(2)<<setfill('0')<<n<<endl;
return 0;
}
}
while(year<=8999){
year++;
month=year%10*10+year%100/10;//年份迴文月
day=year/100%10*10+year/1000;//年份迴文日
if(month>12||day>31) continue;
if(isok(year)) a[1]=29;
else a[1]=28;
if((flag!=1)&&month>0&&month<13&&day>0&&day<=a[month-1]){//找回文型
cout<<setw(2)<<setfill('0')<<year<<setw(2)<<setfill('0')<<month<<setw(2)<<setfill('0')<<day<<endl;
flag=1;
}
if((year/1000!=year%10)&&(year%100==month%10*10+month/10)&&(month==day)){//找ABABBABA型
cout<<setw(2)<<setfill('0')<<year<<setw(2)<<setfill('0')<<month<<setw(2)<<setfill('0')<<day<<endl;
break;
}
}
return 0;
}
試題H 子串分值(20分)
【問題描述】
對於一個字串 S,我們定義 S 的分值 f (S ) 為 S 中出現的不同的字元個
數。例如 f (”aba”) = 2, f (”abc”) = 3, f (”aaa”) = 1。
現在給定一個字串 S [0:n − 1](長度為 n),請你計算對於所有 S 的非空
子串 S [i: j](0 ≤ i ≤ j < n), f (S [i: j]) 的和是多少。
【輸入格式】
輸入一行包含一個由小寫字母組成的字串S。
【輸出格式】
輸出一個整數表示答案。
【樣例輸入】
ababc
【樣例輸出】
28
【樣例說明】
子串 f值
a 1
ab 2
aba 2
abab 2
ababc 3
b 1
ba 2
bab 2
babc 3
a 1
ab 2
abc 3
b 1
bc 2
c 1
【評測用例規模與約定】
對於20% 的評測用例,1 ≤ n ≤ 10;
對於40% 的評測用例,1 ≤ n ≤ 100;
對於50% 的評測用例,1 ≤ n ≤ 1000;
對於60% 的評測用例,1 ≤ n ≤ 10000;
對於所有評測用例,1 ≤ n ≤ 100000。
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int id[27][maxn],nu[27],b[27];//下標
char a[maxn];
long long ans;
int main()
{
cin >> (a+1);
int len=strlen(a+1);
for(int i=1;i<=len;i++)
id[a[i]-'a'][++nu[a[i]-'a']]=i;//記錄每個字母出現的下標
for(int i=1;i<=len;i++)//計算以i開頭的子串的貢獻
{
int top=0;
for(int j=0;j<=25;j++)//記錄每個字母最快出現在i之後的下標
{
if( id[j][ nu[j] ] >= i )//假如出現最晚的這個字母比i大才去查詢,而且需要是第一次出現
{
int index = lower_bound(id[j],id[j]+1+nu[j],i)-id[j];//二分查詢加速
b[++top] = id[j][index];
}
}
sort(b+1,b+1+top);//對每個字母的出現時間排序
int last = i;
for(int j=2;j<=top;j++)
{
ans += ( b[j]-last )*(j-1) ;
last = b[j];
}
ans += ( len-last+1 )*top;
}
cout << ans;
}
試題I 平面切分(25分)
【問題描述】
平面上有 N 條直線,其中第 i 條直線是 y = Ai · x + Bi。
請計算這些直線將平面分成了幾個部分。
【輸入格式】
第一行包含一個整數 N。
以下 N 行,每行包含兩個整數 Ai; Bi。
【輸出格式】
一個整數代表答案。
【樣例輸入】
3
1 1
2 2
3 3
【樣例輸出】
6
【評測用例規模與約定】
對於 50% 的評測用例, 1 ≤ N ≤ 4, −10 ≤ Ai; Bi ≤ 10。
對於所有評測用例, 1 ≤ N ≤ 1000, −100000 ≤ Ai; Bi ≤ 100000。
#include<iostream>
#include<cstring>
#include<set>
using namespace std;
set<pair<double,double> > se;
const int N = 1005;
double A[N];
double B[N];
set<pair<double,double> > s;
set<pair<double,double> >::iterator it;
int main()
{
int n,i,j,x,y;
cin>>n;
for(i=0;i<n;i++)
{
cin>>x>>y;
s.insert(make_pair(x,y));
}
n = s.size();
for(i=0,it=s.begin(),it++;it!=s.end();it++,i++)
{
A[i]=(*it).first;
B[i]=(*it).second;
}
long long ans=2;
for(i=1;i<n;i++)
{
set<pair<double,double> > se;
for(j=i-1;j>=0;j--)
{
double x=(B[j]-B[i])/(A[i]-A[j]);
double y=(A[j]*B[i]-A[i]*B[j])/(A[j]-A[i]);
se.insert(make_pair(x,y));
}
int n2=se.size();
ans+=(n2+1);
}
cout<<ans<<endl;
}
試題J 字串排序(25分)
【問題描述】
小藍最近學習了一些排序演算法,其中氣泡排序讓他印象深刻。
在氣泡排序中,每次只能交換相鄰的兩個元素。小藍發現,如果對一個字串中的字元排序,只允許交換相鄰的兩個字元,則在所有可能的排序方案中,氣泡排序的總交換次數是最少的。
例如,對於字串 lan 排序,只需要 1 次交換。對於字串 qiao 排序,總共需要 4 次交換。
小藍找到了很多字串試圖排序,他恰巧碰到一個字串,需要 V 次交換,可是他忘了把這個字串記下來,現在找不到了。
請幫助小藍找一個只包含小寫英文字母且沒有字母重複出現的字串,對該串的字元排序,正好需要 V 次交換。如果可能找到多個,請告訴小藍最短的那個。如果最短的仍然有多個,請告訴小藍字典序最小的那個。請注意字串中可以包含相同的字元。
【輸入格式】
輸入的第一行包含一個整數V,小藍的幸運數字。
【輸出格式】
題面要求的一行字串。
【樣例輸入】
4
【樣例輸出】
bbaa
【樣例輸入】
100
【樣例輸出】
jihgfeeddccbbaa
【評測用例規模與約定】
對於 30% 的評測用例, 1 ≤ V ≤ 20。
對於 50% 的評測用例, 1 ≤ V ≤ 100。
對於所有評測用例, 1 ≤ V ≤ 10000。
由於限定的的合法字元只有 26 個字母,假設沒有這個約束可以直接按完全逆序排序使得長度最小,然後在消去部分逆序數。而對於這題,首先字母是可以重複的,並且在長度相同若要保證字典序更小顯然要讓較大的字母數量較少,此時只要讓較小的字母較多即可。
這裡可能會陷入一個可貪心的思維誤區:這也是我下面展示的一個假演算法的例子:錯誤點在字典序最優是一個全域性的特性,區域性字典序最優不能保證全域性字典序最優,所以正解應該是搜尋+剪枝。
假演算法
#include <bits/stdc++.h>
using namespace std;
const int N = (int)1e4+5;
int num[N];
int main() {
int n, m;
int _max, id, len, sum;
scanf("%d", &n);
sum = 0; len = 0;
while (sum < n) {
id = 1;
for (int i = 2; i <= 26; i++) { //找到s最小的點, 如果存在多個取字典序更小的
if (num[i] < num[id]) id = i;
}
sum = sum + len - num[id];
len ++;
num[id] ++;
}
m = sum - n; //注意更新逆序數差值
for (int i = 1; i <= 26; i++) {
if (num[i]) {
_max = i;
}
}
for (int i = _max; i >= 1; i--) {
for (int j = 0; j < num[i]; j++) {
printf("%c", 'a'+i-1);
}
}
printf("\n");
for (int i = 1; i <= m; i++) {
for (int j = _max; j >= 1; j--) {
id = 0;
while(num[++id]!= num[j]);
if (id != j) {
num[id] ++;
num[j] --;
break;
}
}
if (!num[_max]) {
_max--;
}
}
for (int i = _max; i >= 1; i--) {
for (int j = 0; j < num[i]; j++) {
printf("%c", 'a'+i-1);
}
}
printf("\n");
return 0;
}
搜尋+剪枝
#include <bits/stdc++.h>
using namespace std;
const int N = (int)1e4+5;
int num[N], res[N];
int n, m, _max, len;
bool judge(int letter) {
int i = 26, j = letter;
while (!res[i]) i--;
if (i == j) {
while (i > 0 && j > 0) {
if (res[i] != num[j]) {
return res[i] > num[j];
} else {
i--; j--;
}
}
}
return i > j;
}
void dfs(int letter, int curlen, int cursum, int l) {
if (cursum > n) return ;
if (letter > _max) return ;
if (curlen > len) return ;
if (curlen == len && cursum != n) return ;
if (letter == _max && cursum != n) return ;
if (cursum == n) {
if (curlen < len || judge(letter)) { //長度減小或字典序減小更新結果
len = curlen;
for (int i = 1; i <= 26; i++) {
res[i] = num[i];
}
}
return ;
}
for (int i = 1; i <= l; i++) {
num[letter + 1] = i;
dfs(letter + 1, curlen + i, cursum + i * curlen, i);
}
num[letter + 1] = 0;
}
int main() {
scanf("%d", &n);
m = 0; len = 0;
while (m < n) {
int id = 1;
for (int i = 2; i <= 26; i++) { //找到s最小的點, 如果存在多個取字典序更小的
if (res[i] < res[id]) id = i;
}
m += len - res[id];
_max = max(_max, id);
len ++; res[id] ++;
}
dfs(0, 0, 0, 10);
for (int i = _max; i >= 1; i--) {
for (int j = res[i]; j > 0; j--) {
printf("%c", i-1+'a');
}
}
printf("\n");
return 0;
}
相關文章
- 2017省賽藍橋杯B組
- 2018藍橋杯省賽B組
- 2015年藍橋杯六屆省賽大學B組真題
- 2017第八屆藍橋杯C/C++ B組省賽第二題 秒解C++
- 藍橋杯省賽真題2013題解
- 第十三屆藍橋杯省賽C/C++ B組C++
- 2016年藍橋杯C/C++組省賽第二題--生日蠟燭C++
- 試題B:小球反彈(第十五屆藍橋杯省賽B組c/c++組)C++
- 第六屆藍橋杯省賽CC++B組C++
- 第十一屆藍橋杯省賽CC++組第二場比賽C++
- 第十四屆藍橋杯省賽C++ B組(個人經歷 + 題解)C++
- 【藍橋杯考前突擊】第十屆藍橋杯省賽C/C++大學B組 試題 D 數的分解C++
- 第九屆藍橋杯B組省賽———乘積最大
- 2016年藍橋杯C/C++組省賽第三題--湊算式C++
- 2016年藍橋杯C/C++組省賽第四題--快速排序C++排序
- 【題解】爬山 藍橋杯2024省B
- 第十五屆藍橋杯軟體賽省賽C/C++B 組題解C++
- 2016年藍橋杯C/C++組省賽第一題--煤球數目C++
- 第十三屆藍橋杯省賽A組
- 2016年省賽第七屆藍橋杯B組C/C++第九題解 交換瓶子C++
- 2019年省賽第十屆藍橋杯B組C/C++試題H解 等差數列C++
- 第十五屆藍橋杯C++B組省賽總結C++
- 第十屆藍橋杯省賽C++B組 等差數列C++
- 第九屆藍橋杯軟體類省賽 Java B組 題目及解析Java
- 第十屆藍橋杯C++國賽B組部分題解(假題解)C++
- 藍橋杯真題
- 第14屆藍橋杯B組國賽
- 2018年第九屆藍橋杯省賽試題及詳解(Java本科B組)Java
- 2015年省賽第六屆藍橋杯B組C/C++第五題解 九陣列分數C++陣列
- 第十五屆藍橋杯大賽軟體賽省賽 C/C++ 大學 A 組C++
- 歷屆藍橋杯省賽(C、C++)的答案(轉)C++
- 2018第九屆藍橋杯省賽C++B組【第四題:測試次數】C++
- 2013第四屆藍橋杯省賽C++B組【第六題:三部排序】C++排序
- 藍橋杯省賽真題2015年第六屆Java本科B組第01題——三角形面積Java
- 藍橋杯第五屆省賽題目及題解
- 2013藍橋杯題解c組C++C++
- 2016藍橋杯省賽第七題剪郵票
- 2015藍橋杯省賽javaA組-----牌型種數(填空)Java