前言:
大學以來 oi 的比賽基本沒參加過,就連網上的線上比賽也是如此。之後要參加 csp,如今打一些線上比賽積累下經驗,並總結。
總的來說題目應該算是比較簡單(當然對於我來說還是不輕鬆)。出現的需要自己解決的問題爲:
- 着急做題而不好好分析題,甚至不好好看題。
- 做題速度慢,不過這一點也沒什麼好辦法,只能慢慢練了。
接下來總結一下各個題的得失。
試題A:完美車牌
描述
有一些數字可以顛倒過來看,例如0、1、8顛倒過來還是本身,6顛倒過來是9,9顛倒過來看還是6,其他數字顛倒過來不構成數字。
類似的,一些多位數也可以顛倒過來看,比如1061倒過來是901.
假設某個城市的車牌只由6位數字組成,每一位都可以取0到9。請問這個城市最多有多少個車牌180°倒過來恰好還是原來的車牌?
例如:車牌號:886988,倒過來還是886988
【答案提交】
這是一道結果填空的題,你只需要算出結果後提交即可。本題的結果爲一個整數,在提交答案時只填寫這個數字,填寫多餘的內容將無法得分。
解答:
方法1:這個車牌號只可能包含0,1,8,6,9
於是,當確定了車牌號的前3位,那後3位是唯一的。
所以5 * 5 * 5 = 125就好了。
方法2:
6個for循環嵌套,枚舉每一個數字上的值,然後逐一判斷,是否滿足要求
答案:125
總結:
我用的第二種方法,一開始我就把題沒看完整導致一開始做錯了,之後反應過來又用的第二種方法。這就是典型的前言中的第一個問題,磨刀不誤砍柴工,比賽時就算題目再多也要一道一道做,也要一個一個認真分析。
試題B:完美日期
描述
不知天上宮闕,今夕是何年。
對於完美日期yyyy/mm/dd,wlxsq的定義是:
- 年月日中均沒有出現數字4,
- 年月日的數位之和是8的倍數
例如:2020/02/02 就是一個完美日期,沒有出現數字4,且數位之和是8的倍數。
wlxsq想知道從2020/02/22開始,第88個完美日期是哪個?
【答案提交】
這是一道結果填空的題,你只需要算出結果後提交即可。本題的結果爲一個格式yyyy/mm/dd,在提交答案時直接填寫這個日期,注意需要如果答案有前導零則不能忽略,填寫多餘的內容將無法得分。
解答:
題目比較簡單,直接模擬即可,只要認真一點都可以做對。
總結:
在敲代碼的過程中我還是很嚴謹的,但是錯在了哪裏呢?就是題目給的例子是 2020/02/02,但是讓從 2020/02/22 開始算,我看成了還是以前者開始算。這就說明還是讀題不認真,所以讀題認真纔是對自己最負責任的行爲。
試題D:完美運算
描述
定義a1:表示數字A對應的三進制數位中1的個數
定義a2:表示數字A對應的三進制數位中2的個數
定義完美運算A○B,如果|a1-a2| = |b1-b2|,A○B的值爲1,否則爲0.請問,在[1,2020] 區間,有多少對(A,B)的結果爲1
例如:A=2,B=3,則a1=0,a2=1,b1=1,b2=0,滿足|a1-a2| = |b1-b2|所以A○B的結果爲1。
注意,A=2,B=3構成的數對(2,3)與A=3,B=2構成的數對(3,2)算同一對。
更新:(2,2)也算一對哦~
【答案提交】
這是一道結果填空的題,你只需要算出結果後提交即可。本題的結果爲一個整數,在提交答案時只填寫這個整數,填寫多餘的內容將無法得分。
解答:
思路簡單,即模擬即可,但有些地方需要總結一下。
#include <cstdio>
#include <utility>
#include <algorithm>
using namespace std;
const int RANGE = 2020;
pair<int,int> tools[RANGE + 10];
int num = 0;
pair<int,int> alt(int n)
{
int temp;
int first = 0,second = 0;
while(n > 0){
temp = n%3;
n /= 3;
if(temp == 1) first++;
else if(temp == 2) second++;
}
return make_pair(first,second);
}
bool judge(int A,int B)
{
if(A == B) return true;
else{
if(abs(tools[A].first - tools[A].second) == abs(tools[B].first - tools[B].second))
return true;
else
return false;
}
}
void get_ans()
{
for(int i = 1;i <= RANGE;i++){
for(int j = i;j <= RANGE;j++){
if(judge(i,j)) num++;
}
}
printf("%d",num);
}
void init()
{
for(int i = 1;i <= RANGE;i++){
tools[i] = alt(i);
}
}
int main()
{
init();
get_ans();
return 0;
}
總結:
- 一個最老生常談,也是最容易避免的問題,那就是認真讀題,這纔是總結的第四題就已經是我第三次說這個問題了。說明我現在太浮躁,一定要狠下心改正。這道題說(2,3)(3,2)這樣的情況算一對,而我沒看到,導致結果多了。
- 在統計一個數三進制下 1、2 個數時,因爲局部變量沒有初始化導致初值成了隨機數,這也是自己的習慣不好,一定要改正。因爲這種寫法表明了我的水平是很低的,這個問題在技術含量上是容易的,但卻不一定容易改正,所以關於這種類型的問題一定要下功夫讓自己養成好習慣。因爲在賽場上這種問題是容易被忽略的,也是不容易發現的,所以很重要。
- 這道題雖然是一道很簡單的模擬題,但是我在第一次求解的過程中沒有使用散列,導致了重複計算。因爲這道題規模不大的緣故,所以無所謂。但是這給我的經驗是,即使是使用暴力、模擬等比較直接的方法,在具體的實現過程中也是可以優化的,不剪枝。剪枝是一種藝術,也是我們追求算法的一種品質,即不斷地思考,來使得求解有效。這也是需要我在平時需要養成的好習慣。
試題G:JM boy 去爬山
描述
疫情終於終於得到了一定的控制~
JM boy在家宅了又宅,宅了又宅,總算是可以帶上口罩出去爬山運動了~
JM boy在爬完山之後,發現自己爬的山像及了一個數列。山是有山峯山谷的,而數列也是可以定義山峯山谷的。
例如,對於某n個數的一種排列,如果不存在任意的i使得A_i > A_{i+1} < A_{i+2},則稱該種排列爲山峯排列。
JM boy想知道,對於1……n的n個數的數列,該數列有多少種排列是屬於山峯排列的。
當然,對於n=1及n=2的情況,肯定是所有的排列都屬於山峯排列了。
輸入
輸入一個整數n,表示數列元素的個數。
輸出
輸出山峯排列的個數。
樣例
輸入
1
輸出
1
輸入
3
輸出
4
提示
【樣例2解釋】
共有以下4種方案: 123、132、231、321
【數據規模】
對於60%的數據 n <= 10
對於100%的數據 n <= 60
解答:
首先分析題目(這很重要),通過讀題最重要的是要知道題目問的是什麼,將問題轉化一下發現其實滿足題目要求的數列只能是一段升序數列後跟一段降序數列。也就是說,最大值任取一個點,該點之前爲升序序列,該店之後爲降序序列。
比如1、2、3、4、5、6,當 6 在第三個位置時,前面的兩個數爲升序序列,後面的三個數爲降序序列。前面兩個數通過 選出,那麼後面的三個數肯定也就確定了。這樣,所有滿足條件的排序數位 ,即由二項式定理得結果爲 ,即。
下面給出代碼:
#include <cstdio>
typedef long long LL;
//a^b
LL quick_pow(LL a,LL b)
{
LL ans = 1;
while(b > 0){
if(b&1) ans *= a;
a *= a;
b >>= 1;
}
return ans;
}
int main()
{
int n;
scanf("%d",&n);
if(n == 1||n == 2) printf("%d",n);
else printf("%lld",quick_pow(2,n-1));
return 0;
}
總結:
對自己真是有點失望了,沒想到這是我這場比賽又一次看錯題。題目最後一條特地給了 1、2得情況,而我卻一掃而過,錯誤得把它理解成了特殊情況,認爲1、2時答案都爲 1,使得一個測試點沒過。
多的不說了,一定要冷靜下來。
後記:
之後的三道題我沒做,其中倒數第三到有了想法,但是沒時間了。總的來說這種簡單題我認真做是可以作對的,但效率比較低。目前努力的方向就是不怕看題費時間,一定要保證正確率,29號第三次模擬賽,衝啊 !