記錄刷題的過程、感悟、題解。
希望能幫到,那些與我一同前行的,來自遠方的朋友😉
大綱:?
?1、空間-(題解)-字節單位轉換
?2、卡片-(題解)-可以不用當組合來寫,思維題
?3、直線-(題解)-數學知識y=ax+b、+模擬
?4、貨物擺放-(題解)-鍛煉巧妙預處理的方式
?5、路徑-(題解)-披著圖論的,dp🥲,怪嚇人、其實跟圖論沒啥關系
?6、時間顯示-(題解)-時間轉換與printf格式輸出
?7、砝碼稱重-(題解)-一道線性dp
?8、楊輝三角形-(題解)-組合數+觀察模擬
?9、雙向排序-(題解)-真 · 靠觀察,天才門,腦洞大開吧
題目:?
1、空間
本題為填空題,只需要算出結果后,在代碼中使用輸出語句將所填結果輸出即可。
小藍準備用?256MB 的內存空間開一個數組,數組的每個元素都是?32?位 二進制整數,如果不考慮程序占用的空間和維護內存需要的輔助空間,請問?256MB 的空間可以存儲多少個?32?位二進制整數?
運行限制
- 最大運行時間:1s
- 最大運行內存: 128M
?/* 基礎知識?
1TB=1024GB
1GB=1024MB
1MB=1024KB
1KB=1024B(字節)
1B=8b(bit)
*/
// int 32位,4字節B ?
#include <bits/stdc++.h>
using namespace std;int main(){cout<<256*1024*1024/4<<endl;return 0;
}
2、卡片
問題描述
小藍有?k?種卡片, 一個班有?n?位同學, 小藍給每位同學發了兩張卡片, 一 位同學的兩張卡片可能是同一種, 也可能是不同種, 兩張卡片沒有順序。沒有 兩位同學的卡片都是一樣的。
給定?n, 請問小藍的卡片至少有多少種?
輸入格式
輸入一行包含一個正整數表示 n?。
輸出格式
輸出一行包含一個整數, 表示答案。
樣例輸入
6
樣例輸出
3
樣例說明
小朋友們手中的卡片可能是:?(1,1),(1,2),(1,3),(2,2),(2,3),(3,3)。
評測用例規模與約定
對于?50?的評測用例,?1≤n≤104。
對于所有評測用例,?1≤n≤109。
運行限制
- 最大運行時間:1s
- 最大運行內存: 256M
其實這題,是可以不用動態規劃。
簡單的推導就行,簡答的考察了一下思維。
??
大家看到了什么
第一個3個、2個、1個...倒序,對吧!就是根據這個,
你能簡單的計算一下區間數量。(1、3、6...)從而逆向求出需要幾張卡片。
舉例:有5個小朋友,2張卡片,只能區分3個。而3張卡片能區分6個。所以,需要3張卡片。
#include <bits/stdc++.h>
#define int long long
using namespace std;signed main(){int n;cin>>n;int cnt = 1;int sum = 1; // 能夠表示的個數 while(true){if(sum>=n) break;cnt++;sum+=cnt;} cout<<cnt<<endl;return 0;
}
3、直線
題目描述
本題為填空題,只需要算出結果后,在代碼中使用輸出語句將所填結果輸出即可。
在平面直角坐標系中,兩點可以確定一條直線。如果有多點在一條直線上, 那么這些點中任意兩點確定的直線是同一條。
給定平面上 2 × 3 個整點(x,y)∣0≤x<2,0≤y<3,x∈Z,y∈Z,即橫坐標 是?0?到?1?(包含 0 和 1) 之間的整數、縱坐標是 0 到 2 (包含 0 和 2) 之間的整數 的點。這些點一共確定了 11 條不同的直線。
給定平面上?20×21 個整點?(x,y)∣0≤x<20,0≤y<21,x∈Z,y∈Z,即橫 坐標是?0?到?19?(包含?0?和?19) 之間的整數、縱坐標是?0?到?20?(包含?0?和?20?) 之 間的整數的點。
請問這些點一共確定了多少條不同的直線。
運行限制
- 最大運行時間:1s
- 最大運行內存: 128M
// 其實本題,能轉化成簡單的數學問題,也就是 是不是一條線的問題?
// 咱們這道題:
/*
? 既然要找線段,首先就要確定兩個點,從而確定一條線
? 但是有一種情況是,線段可能重復計算
? 排除重復的前提是,首先需要確定這條線:?
? 這時,我們可以根據公式 y=kx+b; ?
? 我們可以根據 k 、b兩個值,確定這條直線
? (a1、b1)(a2、b2)
? : b1 = ka1 + b
? : b2 = kb2 + b
? k = (b1-b2)/(a1-a2);
? b = (a1*b2-a2*b1)/(a1-a2) -- 切記,這是化簡之后的。
? 如果不化簡,可能導致,精度損失過大,導致誤判!!!?
??
? 當然,在計算過程中,要排除一種情況,就是k無限大的可能。90°時,無限大。
? 但只有20個,直接跳過,可以在結尾上加入。
??
? 但是,前提要用set這個函數。 因為紅黑樹重載了pair,能用 < 比較
? 但是unordered_set,沒有重載pair的哈希?
*/
#include <bits/stdc++.h>
using namespace std;int main(){set<pair<double,double>> set; for(int a1=0; a1<20; ++a1){for(int b1=0; b1<21; ++b1){// 位置第一個(i,j)位置for(int a2=0; a2<20; ++a2){for(int b2=0; b2<21; ++b2){// 位置第二個(x,y)位置,現在,咱們知道了,兩個位置,也可以開始計算了// 這個時候,要排除兩個點:if(a1==a2) continue; // 當a1==a2的情況時 b1==b2重疊,b1!=b2 垂直double k = (double)(b1-b2)/(a1-a2);double b = (double)(a1*b2-a2*b1)/(a1-a2);set.emplace(k,b);}}}}cout<<set.size()+20<<endl;return 0;
}
4、貨物擺放
題目描述
小藍有一個超大的倉庫,可以擺放很多貨物。
現在,小藍有?n?箱貨物要擺放在倉庫,每箱貨物都是規則的正方體。小藍規定了長、寬、高三個互相垂直的方向,每箱貨物的邊都必須嚴格平行于長、寬、高。
小藍希望所有的貨物最終擺成一個大的長方體。即在長、寬、高的方向上分別堆?L、W、H?的貨物,滿足?n=L×W×H。
給定?n,請問有多少種堆放貨物的方案滿足要求。
例如,當?n=4 時,有以下?6?種方案:1×1×4、1×2×2、1×4×1、2×1×2、2×2×1、4×1×1。
請問,當?n=2021041820210418(注意有?16?位數字)時,總共有多少種方案?
提示:建議使用計算機編程解決問題。
答案提交
這是一道結果填空的題,你只需要算出結果后提交即可。本題的結果為一個整數,在提交答案時只填寫這個整數,填寫多余的內容將無法得分。
/*
?? ?講一個冷知識,普遍大家的編輯器,1s空轉大概也就1e8次~1e9次之間
?? ?而本題大概有1e16次方這么大,所有就不要有不切實際的幻想啦!
?? ?所以做這種題目,不要懷疑!直接對數據提前處理。?
?? ?就算預處理,依然要考慮一件事情,就是怎么處理16位數據。
?? ?對題目分解,你或許會發現,其實本題參與運算的,其實都是質因數。
? 當然,這里有一個冷知識,注意開辟數組的大小。int類型數組,開到1e8大概400MB,long long為800MB(都會內存越界),所以開到1e7最為合適。
*/
#include <bits/stdc++.h>
#define int long long
const int N = 1e7;
int arr[N];
using namespace std;signed main(){int sum = 2021041820210418;int cnt = 0;// 通過巧妙的數學思維,轉換高緯度運算。并且求值 for(int i=1; i*i<=sum; ++i){ if(sum%i==0) arr[cnt++]=i;if(sum%i==0&&sum/i!=i) arr[cnt++]=sum/i; // 切記,千萬別忘加sum%i,否則會導致誤判很多 } int res = 0;for(int i=0; i<cnt; ++i)for(int j=0; j<cnt; ++j)for(int k=0; k<cnt; ++k)if(arr[i]*arr[j]*arr[k]==sum) res++;cout<<res<<endl;return 0;
}
5、路徑
本題為填空題,只需要算出結果后,在代碼中使用輸出語句將所填結果輸出即可。
小藍學習了最短路徑之后特別高興,他定義了一個特別的圖,希望找到圖 中的最短路徑。
小藍的圖由 2021 個結點組成,依次編號 1 至 2021。
對于兩個不同的結點 a, b,如果 a 和 b 的差的絕對值大于 21,則兩個結點 之間沒有邊相連;如果 a 和 b 的差的絕對值小于等于 21,則兩個點之間有一條 長度為 a 和 b 的最小公倍數的無向邊相連。
例如:結點 1 和結點 23 之間沒有邊相連;結點 3 和結點 24 之間有一條無 向邊,長度為 24;結點 15 和結點 25 之間有一條無向邊,長度為 75。
請計算,結點 1 和結點 2021 之間的最短路徑長度是多少。
提示:建議使用計算機編程解決問題。
運行限制
- 最大運行時間:1s
- 最大運行內存: 128M
/*
?? ?如果,真的把這道題目當作圖論來寫,那就真是小可愛。
?? ?怎么說呢,就是一道,血脈純正的dp,與圖真的,不太沾邊
?? ?但是,寫這道題目的前提是,
?? ?你要會求解 lcm,而求解lcm的前提是,你會求解 gcd。
?? ?當這一切搞定,那就理所應當的開始dp之旅吧?
?? ?dp[i]的,定義可以看作是 到達i 所走的距離?
*/
#include <bits/stdc++.h>
using namespace std;int dp[2070]; // 稍稍開大一點
int gcd(int a, int b){return a%b==0?b:gcd(b,a%b);
}
int main(){// dp[i]代表,到達i所走的距離 for(int i=1; i<=2021; ++i){for(int j=i+1; j<=i+21; ++j){ // 當然是算21的差距啦 if(dp[j]==0) dp[j]=dp[i]+i*j/gcd(i,j);else dp[j]=min(dp[j],dp[i]+i*j/gcd(i,j)); }}cout<<dp[2021]<<endl;return 0;
}
6、時間顯示
題目描述
小藍要和朋友合作開發一個時間顯示的網站。
在服務器上,朋友已經獲取了當前的時間,用一個整數表示,值為從?1970 年?11?月?11?日?00:00:00 到當前時刻經過的毫秒數。
現在,小藍要在客戶端顯示出這個時間。小藍不用顯示出年月日,只需要顯示出時分秒即可,毫秒也不用顯示,直接舍去即可。
給定一個用整數表示的時間,請將這個時間對應的時分秒輸出。
輸入描述
輸入一行包含一個整數,表示時間。
輸出描述
輸出時分秒表示的當前時間,格式形如?
HH:MM:SS
,其中?HH
?表示時,值為?0???? 到?23????,MM
?表示分,值為?00????到?59???,SS
?表示秒,值為?0?? 到?59?。時、分、秒 不足兩位時補前導?0。輸入輸出樣例
示例 1
輸入
46800999
輸出
13:00:00
示例 2
輸入
1618708103123
輸出
01:08:23
評測用例規模與約定
對于所有評測用例,給定的時間為不超過?10^18?的正整數。
// 毫秒的計算單位
// 當時的思考過程:先求出,有多少秒,在求出,有多少分,最后在求出,有多少小時,本題跟年、月無關
// 炸了,無論怎么寫,好像都不對
// printf ?. 的位置,哪里錯了??!!!
/*
? ? ? 其實這里有兩點需要注意:1s=1000ms; 1ms=1000ns
? ? ? 第二點,就是printf()的格式說明。
·? ? ? ? 1、整數補零格式:printf("%02lld",a);補成3的格式:printf("%32lld",a);不足兩位的補成3
? ? ? ? ?2、精度(四舍五入)的格式 printf("%.4lf",a);小數點后4位
*/
#include <bits/stdc++.h>
#define int long long
using namespace std;
// 毫秒的計算單位signed main(){int sum;cin>>sum;int ss = (sum/1000)%60; // 有多少秒int mm = (sum/1000/60)%60; // 有多少分int hh = (sum/1000/60/60)%24; // 求有多少小時printf("%02lld:%02lld:%02lld",hh,mm,ss);return 0;
}
7、砝碼稱重
問題描述
你有一架天平和?N?個砝碼,這?N?個砝碼重量依次是?W1,W2,???,WN?。
請你計算一共可以稱出多少種不同的重量? 注意砝碼可以放在天平兩邊。
輸入格式
輸入的第一行包含一個整數?N。
第二行包含?NN?個整數:W1,W2,W3,???,WN?。
輸出格式
輸出一個整數代表答案。
樣例輸入
3 1 4 6
樣例輸出
10
樣例說明
能稱出的?10?種重量是:1、2、3、4、5、6、7、9、10、11。
1=1;
2=6?4(天平一邊放?6,另一邊放 4);?
3=4?1;
4=4;
5=6?1;
6=6;
7=1+6;
9=4+6?1;
10=4+6;
11=1+4+6。
評測用例規模與約定
對于?50的評測用例,1≤N≤15。
對于所有評測用例,1≤N≤100,N?個砝碼總重不超過?100000。
運行限制
- 最大運行時間:1s
- 最大運行內存: 256M
// 要給出暴力解法
/*
?? ?怎么說呢,這道題目,都暗示的這么明顯了。
?? ?其實多少有點背包問題的味道。
?? ?但,他可比背包問題,多了不同的情況
?? ?(背包問題考慮的是,放還是不放
?? ?(砝碼問題,考慮的是,放的時候,放左邊,還是放右邊,或者不放
?? ?所以大膽的設dp值:dp[i][j] 含義是第i個砝碼,能夠稱出的重量為j
?? ?遞推公式,更易推導出來
?? ?咱們這里先舉出所有遞推公式:?
?? ?( dp[i-1][j];
?? ?( dp[i-1][abs(j-w)]
?? ?( dp[i-1][j+w]
?? ?放入第i個砝碼時,判斷能否稱出重量k 是由上一個砝碼決定的。?
?? ?如本題:1 4 6
?? ?dp[i-1][j]?
?? ?當輪到砝碼6時,判斷是否能稱出1時,dp[i][k]=dp[i-1][k],直接判斷之前是否出現這種情況。
?? ?dp[i-1][j+w]
?? ?大家可以找一個,他的作用是,放在天平兩側?
?? ??? ??? ??? ??? ?1、4、6無法舉出好例子,當如果i-1時,能稱出,12這個重量,那么dp[i-1][12-6]就相當于稱出了6這個重量。?
?? ?dp[i-1][abs(j-w)],公式推導,天平放在同一側。?
?? ?當輪到砝碼6時,判斷能否稱出2這個重量時,2-6;-->看的就是 是否存在 dp[i-1][abs(2-6)]--dp[i-1][abs(i-j)];
?? ??? ??? ??? ? ? 判斷是否能稱出砝碼10時,10-6;--> 看的就是 是否存在 dp[i-1][abs(10-6)]--dp[i-1][abs(i-j)];
?? ??? ??? ??? ? ? 注:其實,j-w<0時,就相當于,放在了天平兩側 ?? ??
*/
#include<bits/stdc++.h>
using namespace std;
const int N = 1e2+5;
const int W = 2e5+5; int dp[N][W];
int weight[N];
int main(){memset(dp,0,sizeof dp);int n; // 表示有幾個砝碼cin>>n; for(int i=1; i<=n; ++i) cin>>weight[i]; // 天吶,簡直了dp[0][0]=1;for(int i=1; i<=n; ++i){int w = weight[i]; // 原來是這樣子的呢。for(int k=0; k<100001; ++k){ // 原來是這樣子的呢。的呢。 if(dp[i-1][k]) dp[i][k]=dp[i-1][k];else {dp[i][k]=max(dp[i-1][abs(k-w)],dp[i-1][k+w]); }} } int cnt = 0;for(int i=1; i<100001; ++i) if(dp[n][i]) cnt++;cout<<cnt;return 0;
}
8、楊輝三角形
題目描述
下面的圖形是著名的楊輝三角形:
?
如果我們按從上到下、從左到右的順序把所有數排成一列,可以得到如下數列:?1,1,1,1,2,1,1,3,3,1,1,4,6,4,1,?
給定一個正整數?N,請你輸出數列中第一次出現?NN?是在第幾個數?
輸入描述
輸入一個整數?N。
輸出描述
輸出一個整數代表答案。
輸入輸出樣例
示例 1
輸入
6
輸出
13
評測用例規模與約定
對于?20?? 的評測用例,1≤N≤10?; 對于所有評測用例,1≤N≤1000000000。
/*
?? ?能完成這道題目,觀察思維都是次要的,因為,你要首先要知道楊輝三角與組合數的關系。
? ? 當你知道與組合數之間的關系后,再看看y總講解。切記先上網找資料研究一下。
*/?
#include <bits/stdc++.h>
#define int long long
using namespace std;// 為啥>>1 不行???
// 求該數值
int get_num(int n, int m,int num){int res=1;// 這樣避免造成精度損失for(int i=n,j=1; j<=m; i--,j++){res*=i;res/=j;if(res>num) return res; // 避免了,組合數溢出,成為負數的問題}
// for(int i=n,j=m; j>0; i--,j--) res*=i/j;
// 要排除掉這種情況!會造成精度損失 return res;
} bool get_res(int k, int num){int l = 2*k, r=max(num,2*k); // 直接延申有邊界,但是會存在num<2*k的情況. while(l<=r){ // 二分查找,查找第一個大于等于 int mid = l+(r-l)/2;if(get_num(mid,k,num)>=num) r=mid-1;else l=mid+1; } if(get_num(l,k,num)==num) cout<<k+1+(l+1)*l/2<<endl;else return false;return true;
} signed main(){int num;cin>>num;if(num==1){ // 如果是1,就可以直接結束了。 cout<<1<<endl;return 0;}// 開啟二分查找 for(int i=16; i>=1; --i){if(get_res(i,num)) return 0; } return 0;
}
9、雙向排序
題目描述
給定序列?(a1,a2,???,an)=(1,2,???,n),即?ai=i。
小藍將對這個序列進行?mm?次操作,每次可能是將?a1,a2,?,aqi 降序排列,或者將?aqi,aqi+1,?,an??升序排列。
請求出操作完成后的序列。
輸入描述
輸入的第一行包含兩個整數?n,m,分別表示序列的長度和操作次數。
接下來?m? 行描述對序列的操作,其中第 i 行包含兩個整數?pi,qi 表示操作類型和參數。當?pi=0時,表示將?a1,a2,???,aqi降序排列;當?pi=1? 時,表示將?aqi,aqi+1,?, 升序排列。
輸出描述
輸出一行,包含?n?個整數,相鄰的整數之間使用一個空格分隔,表示操作完成后的序列。
輸入輸出樣例
示例
輸入
3 3 0 3 1 2 0 2
輸出
3 1 2
樣例說明
原數列為?(1,2,3)?????。
第?1????? 步后為?(3,2,1)?????。
第?2???? 步后為?(3,1,2)??。
第?3??? 步后為?(3,1,2)。與第?2?步操作后相同,因為前兩個數已經是降序了。
評測用例規模與約定
對于?30%?的評測用例,n,m≤1000;
對于?60%?的評測用例,n,m≤5000;
對于所有評測用例,1≤n,m≤100000,0≤pi≤1,1≤qi≤n。
好啦,這道題目,y總講解的也挺不錯的,大家可以直接食用 :: 傳送門?::?
#include<iostream>
#include<algorithm>
using namespace std;
typedef pair<int,int> PII;
const int N=1e5+7;
PII stk[N];//棧記錄有效操作
int s[N],top;//最后的數組,top為棧的頭指針
int main(){int n,m;cin>>n>>m;while(m--){//m次操作int q,p;cin>>q>>p;if(!q){while(top && stk[top].first==0)p=max(p,stk[top--].second);//對于重復降序,我們只需要保持最長值while(top>=2 && stk[top-1].second<=p)top-=2;//維持交錯的單調性stk[++top]={0,p};}else if(top){while(top && stk[top].first==1)p=min(p,stk[top--].second);while(top>=2 && stk[top-1].second >=p)top-=2;stk[++top]={1,p};}}int l=1,r=n,k=n;for(int i=1;i<=top;i++)//讀取棧if(stk[i].first)//讀取他的正逆序while(l<stk[i].second && l<=r)s[l++]=k--;elsewhile(r>stk[i].second && l<=r)s[r--]=k--;//最后補充未填充的數if(top!=0&&stk[top].first==0) // 若有余數則為降序while(l<=r) s[l++]=k--;else if(top!=0)while(l<=r) s[r--]=k--;for(int i=1;i<=n;i++)cout<<s[i]<<" ";}
最后一道題,哎,一言難進....
知識點:
1、藍橋杯常考基礎知識點:
數據類型與取值范圍
- int類型 32 位系統中,占4個字節,取值范圍是 -2^31 到 2^31-1。
- long類型 一般占8個字節,取值(18個整數左右)
- float類型 占4個字節,用于表示單精度浮點數,有一定的精度范圍。
- double類型 占用8個字節,是雙精度浮點數,精度更高(通常16~17個整數,long double 19個)
進制轉換:
- 二進制、八進制、十進制、十六進制之間轉換,其中十六進制,(十->二)可以使用除2取余法。將二進制轉換為十六進制,可以每位4位一組轉換。
- 位運算與進制之間的關系。如左移一位,相當于乘2
字符編碼:
- ASCII碼:是一種常見編碼,通常由7位、8位二進制數表示一個二進制數表示一個字符。總共可以表示128個 or 256個。
- Unicode編碼:為世界上幾乎所有的字符都分配了一個唯一的數字編號,包括漢字、希臘字母、阿拉伯字母等各種字符集。常見的 Unicode 編碼實現有 UTF-8、UTF-16 等,UTF-8 是一種可變長度的編碼方式,它可以用 1 到 4 個字節來表示一個字符,能夠很好地兼容 ASCII 碼。
計算機存儲單位換算
TB(太字節)、GB(吉字節)、MB、KB(千字節)、B、b;
b(1位、1bit)
B(1字節)
KB = 1024B
MB = 1024KB
時間單位換算
1 秒(s)= 1000 毫秒(ms),1 毫秒 = 1000 微秒(μs),1 微秒 = 1000 納秒(ns)
2、基礎數學知識
- 數論
- 質數:判斷一個數是否為質數、質數的篩選(如埃氏篩法、線性篩法)等。
- 約數:求一個數的約數個數、約數之和,以及最大公約數和最小公倍數的計算方法,如輾轉相除法。
- 同余:同余的概念、性質,以及求解同余方程等。例如,在一些密碼學相關的題目中,可能會用到同余的知識來進行加密和解密操作。
- 組合數學
- 排列組合:計算排列數和組合數,解決一些與計數相關的問題,如在給定條件下的排列方式有多少種,或者從若干元素中選取部分元素的組合方法數等。
- 鴿巢原理:用于解決一些存在性問題,例如證明在一定數量的物體分配到若干個集合中,必然存在某個集合滿足特定條件。
- 容斥原理:計算多個集合的并集元素個數,通過容斥原理可以避免重復計算,在一些復雜的計數問題中經常會用到。
3、概率論與統計學
- 概率計算:計算事件發生的概率,包括古典概型、條件概率、全概率公式等。例如,在一些抽獎、游戲等場景的題目中,需要運用概率知識來分析結果。
- 期望與方差:理解期望和方差的概念,能夠計算隨機變量的期望和方差,用于評估隨機現象的平均水平和波動程度。
4、幾何知識
- 平面幾何:掌握點、線、面的相關性質和計算,如兩點間距離公式、直線的斜率、三角形的面積、相似三角形的性質等。在一些圖形處理、路徑規劃等類型的題目中會用到平面幾何知識。
- 解析幾何:將幾何問題轉化為代數問題進行求解,例如通過建立坐標系,利用直線方程、圓的方程等來解決相關問題。
5、離散數學
- 圖論:圖的基本概念,如頂點、邊、度數、連通圖等;圖的遍歷算法,如深度優先搜索(DFS)、廣度優先搜索(BFS);以及一些經典的圖論算法,如最短路徑算法(迪杰斯特拉算法、弗洛伊德算法)、最小生成樹算法(普里姆算法、克魯斯卡爾算法)等。圖論在解決網絡拓撲、路徑規劃、任務分配等問題中有著廣泛的應用。
- 邏輯推理:命題邏輯、謂詞邏輯的基本概念和推理規則,能夠進行邏輯表達式的化簡、證明以及邏輯推理問題的求解。在一些需要根據給定條件進行推理判斷的題目中,邏輯推理能力是關鍵。
6、
的時間奧秘
通常,他是用到分治法中的,每次區間減半。(如:二分查找)
假設有n個數值,n/2^k=1;
對數轉化:2^k=n? ?:::? ?k =??
所以就是這么求log的時間復雜度的。