本人大一,第一次參加藍橋杯,藍橋杯也是我參加的第一場大賽,真的很緊張,估摸著感覺運氣的成分特別大,做出來了七道題,四道填空題三道編程題,后來對了對答案,填空題對了三道,編程題應該是沒辦法過全部資料,結果居然拿到了省一,有點出乎意料,聽完Y總的講解更是收益匪淺,那就大致寫寫我在賽場上的心路歷程以及我對每道題的一些分析思路,
文章目錄
- 試題A. 空間
- 試題B.卡片
- 試題C. 直線
- 試題D.貨物擺放
- 試題E.路徑
- 填空題總結
試題A. 空間

這道水題沒啥好說的,但凡了解一點計算機的都不會錯,不需要借助編程,注意單位轉換 1MB = 1024 KB = 1024 * 1024 B,32 bit = 4 B 用計算器就可以解決
答案:67108864

試題B.卡片

這題表面上問我們2021個0到9的數字能組成到第多少個數,但其實就是問到多少個數里面包含2021個1, 因為1永遠是最先被用到的,也肯定是最先被用完的,代碼如下
答案:3181
#include<iostream>
using namespace std;
int cnt ;
int main(void)
{
for (int i = 1 ;; i++) {
int temp = i ;
while (temp) {
if (temp % 10 == 1) cnt++ ;
temp /= 10 ;
}
if (cnt == 2021) {
cout << i ;
break ;
}
if (cnt > 2021) {
cout << i - 1 ;
break ;
}
}
return 0 ;
}
試題C. 直線

這題很可惜錯了,思路大體上是對的,利用數學公式把直線的斜率和截距表示出來,我想著用集合去重,后來輸出集合大小應該就沒問題了,但是后來才想起來用浮點數去存k和b會有誤差導致無法完全相等無法去重,所以這條路子不好走通,于是換條路子,利用結構體陣列將每組k和b進行排序,然后如果相差足夠小就當做相等, 這里要注意下當k不存在的情況需要特判一下,
答案:40257
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int N = 200000 ;
int res, n ;
struct node
{
double k ;
double b ;
}arr[N];
bool cmp(node x, node y)
{
if (x.k == y.k) return x.b < y.b ;
return x.k < y.k ;
}
int main(void)
{
for (int x1 = 0 ; x1 < 20 ; x1++) {
for (int y1 = 0 ; y1 < 21 ; y1++) {
for (int x2 = 0 ; x2 < 20 ; x2++) {
for (int y2 = 0 ; y2 < 21 ; y2++) {
if(x1 != x2) {
double k = (double)(y1 - y2) / (x1 - x2) ;
double b = (double)(y1 - k * x1 ) ;
arr[n++] = {k, b} ;
}
}
}
}
}
sort(arr, arr + n, cmp) ;
for (int i = 1 ; i < n ; i++) {
if (fabs(arr[i].k - arr[i - 1].k) > 1e-8 || fabs(arr[i].b - arr[i - 1].b) > 1e-8)
res++ ;
}
cout << res + 20 ;
return 0 ;
}
試題D.貨物擺放

這題我第一眼看以為是暴力剪枝,畢竟藍橋杯又名暴力杯,某位dalao曾和我說他有一次打藍橋杯有一個代碼跑了兩個小時,讓我銘記于心,結果這一次我一直跑到比賽結束都沒有跑出來…
↓錯誤TLE代碼
#include<iostream>
using namespace std;
long long N = 2021041820210418 ;
long long num ;
int main(void)
{
for (long long i = 1 ; i <= N ; i++) {
if (N % i == 0) {
int temp = N / i ;
for (long long j = 1 ; j <= temp ; j++) {
if (temp % j == 0) num++ ;
}
}
}
cout << num ;
return 0 ;
}
現在想想但凡算一下時間復雜度也都知道根本出不來,所以必須換一個思路,先把2021041820210418的所有因子求出來,在進行暴力回圈,這樣可以大大降低時間復雜度,
答案:2430
↓正確AC代碼
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;
long long cnt ;
vector<long long> vec ;
void get_factor(long long n)
{
for (int i = 1 ; i <= sqrt(n) ; i++) {
if (n % i == 0) {
vec.push_back(i) ;
vec.push_back(n / i) ;
}
}
}
int main(void)
{
get_factor(2021041820210418);
for (long long i = 0 ; i < vec.size() ; i++) {
for (long long j = 0 ; j < vec.size() ; j++) {
for (long long z = 0 ; z < vec.size() ; z++) {
if (vec[i] * vec[j] * vec[z] == 2021041820210418) cnt++ ;
}
}
}
cout << cnt ;
return 0 ;
}
這道在我能力范圍內的題沒做出來真的很可惜!!!!
試題E.路徑

這道題乍一看是一道最短路,其實它就是一道最短路, 而且是填空題,不需要考慮時間復雜度,什么最短路演算法都能往上寫,但是在比賽場上的我沒有用最短路也做出來了(其實就是太菜了根本不會最短路演算法,別罵了孩子知錯了),我用的是自以為正確的數學分析外加一點點的蒙居然做(meng)出來了,簡直幸運值拉滿,
↓我的賽場分析程序(看看就好別當真):
這道題大意是說在絕對值小于21的兩個數字之間有無向邊,無向邊長為兩數字的最小公倍數,作為我唯一會的數論:
int gcd(int x, int y) // 求最大公因數
{
return y? gcd(y, x % y) : x ;
}
int lcm(int x, int y) //求最小公倍數
{
return x * y / gcd(x, y) ;
}
那么想要每一步最小公倍數最小,那就讓最大公因數最大即可,每一步之間的最大公因數其實就是在1到21之間,那么如果每一步都走到21的倍數,它們的最大公因數應該最大,最小公倍數就能最小,所以就是從1開始:1,21,42,63…一直到2016,最后再加上2016和2021的最小公倍數,總距離應該就是最小的了,代碼如下:
#include<iostream>
using namespace std;
int gcd(int x, int y)
{
return y? gcd(y, x % y) : x ;
}
int lcm(int x, int y)
{
return x * y / gcd(x, y) ;
}
int main(void)
{
long long num = 1 * 21 / gcd(1, 21) ;
for (int i = 42; i <= 2016 ; i += 21) {
num += (i - 21) * i / gcd(i, i - 21) ;
}
num += 2016 * 2021 / gcd(2016, 2021) ;
cout << num ;
return 0 ;
}
最后結果是10266837,沒有很嚴謹的數學證明,只能說是運氣好,大腦的自以為是對的好像真的是對的,要是因為不會最短路演算法丟掉這一題那就太虧了,最短路的版本題解也將放在后續,
填空題總結
這五道選擇題就我而言是在能力范圍之內的,并不難,錯了兩道確實可惜,只能說自己在比賽場上對題目的分析還不夠全面,不能每次都找到題目的最優解,當時為了跑出那個試題D,我還開了兩個編譯器,我對時間復雜度的計算也不夠熟練,或者說還沒有養成取計算時間復雜度的這個習慣,感覺自己的提升空間還很巨大,趕緊沖刺復習下一些基礎演算法爭取在國賽上面別丟臉qwq

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/282310.html
標籤:其他
下一篇:指標與陣列筆試題決議
