//ps:學習自存,暫未整理。
知識點
演算法:思維,STL,模擬,排序,列舉,查詢,遞推與遞迴,貪心,二分,雙指標,字首和、差分與離散化丨常見最佳化技巧,分治與倍增〔倍增Floyd〕,位運算丨三分,01分數規劃
字串:基礎丨kmp,字典樹,AC自動機,最小表示法,字尾陣列,字尾自動機
資料結構:棧,佇列,線性表,連結串列,二叉樹,集合,圖的基本應用丨並查集,堆(優先佇列),二叉堆與樹狀陣列,線段樹〔基礎,進階〕丨平衡樹,主席樹,RMQ與LCA
搜尋:DFS(深度),BFS(廣度),記憶化搜尋,搜尋與搜尋剪枝丨蒙特卡洛樹搜尋
DP:線性DP,揹包問題丨數位DP,樹形DP,計數DP,區間與環形DP,樹與圖上的DP,丨狀態壓縮DP,動態規劃的設計與最佳化(單調佇列DP)
數學:基礎數學丨輾轉相除法,進階數論,組合數學與計數,機率與統計,基礎線性代數,矩陣加速〔矩陣快速冪〕丨雜湊函式,篩質數,gcd/lcm,快速冪,逆元,擴充套件歐幾里得,費馬小定理,更相減損術,博弈論,機率與統計,基礎線性代數,矩陣加速(矩陣快速冪)
圖論:樹〔樹的直徑〕,最短路(Dijkstra),最小生成樹(Kruskal),連通性問題,分層圖,類Floyd演算法丨二分圖,差分約束,連通分量,網路流,尤拉圖
計算幾何:基礎丨點積,叉積,凸包
演算法
模擬,排序,列舉,貪心,遞推與遞迴,二分,搜尋
字首和、差分與離散化,常見最佳化技巧,分治與倍增,字串,進階搜尋
資料結構
線性表,二叉樹,集合,圖的基本應用
並查集,二叉堆與樹狀陣列,線段樹
線段樹的進階用法
DP
基礎DP
線性狀態動態規劃,區間與環形動態規劃,樹與圖上的動態規劃,狀態壓縮動態規劃,動態規劃的設計與最佳化
數學
基礎數學
進階數論,組合數學與計數,機率與統計,基礎線性代數
圖論
樹,最短路,最小生成樹,連通性問題
難度
無評定
入門
普及−
普及/提高−
普及+/提高
提高+/省選−
省選/NOI−
NOI/NOI+/CTSC
——————————————————————————————————
Review
L1-1 抓兔子,搗年糕
簽到
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
cin >> s;
char ans = s[0]; // 直接初始化為字串的第一個字元,減少一個字元的比較
for (char c : s) ans = min(ans, c); // 使用範圍for迴圈和min函式簡化程式碼
cout << ans << endl;
return 0;
}
L1-2 期初考試
簽到
include
include
using namespace std;
int main() {
int n;
cin >> n; // 輸入考試門數
double sum = 0; // 儲存分數總和,用double以保持精度
for (int i = 0; i < n; ++i) {
int score;
cin >> score; // 輸入每門考試的分數
sum += score; // 累加分數
}
cout << fixed << setprecision(4) << sum / n << '\n'; // 輸出平均分,保留4位小數
return 0;
}
L1-3 慧音老師的銀杏葉
結構體排序
include
include
include
using namespace std;
struct Student {
int id; // 學號
int scores[3]; // 三門課的成績
int total; // 總分
// 建構函式,用於初始化學生資訊
Student(int id, int history, int magic, int virtue) : id(id) {
scores[0] = history;
scores[1] = magic;
scores[2] = virtue;
total = history + magic + virtue;
}
};
// 自定義排序規則
bool compare(const Student &a, const Student &b) {
if (a.total != b.total) return a.total > b.total; // 按總分降序排列
if (a.scores[0] != b.scores[0]) return a.scores[0] > b.scores[0]; // 幻想鄉歷史學成績降序
return a.id < b.id; // 學號升序
}
int main() {
int n;
cin >> n;
vector
for (int i = 1; i <= n; ++i) {
int history, magic, virtue;
cin >> history >> magic >> virtue;
students.emplace_back(i, history, magic, virtue);
}
// 使用自定義的比較函式進行排序
sort(students.begin(), students.end(), compare);
// 輸出前5名學生的學號和成績總分
for (int i = 0; i < 5; ++i) {
cout << students[i].id << " " << students[i].total << "\n";
}
return 0;
}
L1-4 反射Master
數學
include
using namespace std;
int main(){
long long n, p, k;
cin >> n >> p >> k;
cout << (k * p) % n << "\n";
return 0;
}
L1-5 幻想鄉程式設計大賽
列舉
include
include
include
using namespace std;
int main() {
int T;
cin >> T;
while (T--) {
int yl, n, yr;
cin >> yl;
cin >> n;
vector
for (int i = 0; i < n; ++i) {
cin >> stops[i];
}
cin >> yr;
// 計算從yl到yr之間的總年份數(包括yr年)
int totalYears = yr - yl + 1;
// 從總年份數中減去停辦的年份
for (int stopYear : stops) {
if (stopYear <= yr) {
totalYears--;
}
}
cout << totalYears << endl;
}
return 0;
}
L1-6 驚人的秘密
思維
include
include
include
using namespace std;
// 計算修改為特定模式需要的操作次數
int calculateChanges(const string& answers, char first, char second) {
int changes = 0;
for (size_t i = 0; i < answers.length(); ++i) {
// 當前應該是哪個字元
char expected = (i % 2 == 0) ? first : second;
if (answers[i] != expected) {
changes++;
}
}
return changes;
}
int main() {
int n;
string answers;
cin >> n >> answers;
// 計算修改為BCBCBC...和CBCBCB...需要的操作次數
int changesForBC = calculateChanges(answers, 'B', 'C');
int changesForCB = calculateChanges(answers, 'C', 'B');
// 輸出最小操作次數
cout << min(changesForBC, changesForCB) << endl;
return 0;
}
L1-7 賢者的變數替換
雜湊對映 + 字串操作
include
include <unordered_map>
include
using namespace std;
int main() {
unordered_map<string, string> mp;
string s, x;
int n, m;
cin >> n >> m;
while (n--) {
cin >> s >> x;
s = "{" + s + "}";
mp[s] = x;
}
cin.ignore(); // 忽略前一個輸入後的換行符
while (m--) {
getline(cin, s);
for (auto &[t, val] : mp) {
size_t pos = 0;// pos 用於記錄當前查詢的位置。
while ((pos = s.find(t, pos)) != string::npos) {// 在字串 s 中查詢變數名 t。
s.replace(pos, t.size(), val);// 在找到變數名的位置 pos 替換為它的值 val。
pos += val.size(); // 更新 pos 為替換文字之後的位置,以避免替換後的文字被重複查詢。
}
}
cout << s << '\n';
}
return 0;
}
L1-8 上海蓬萊
區間合併
include
include
include
using namespace std;
int main() {
int n;
cin >> n;
vector<pair<int, int>> dolls(n);
for (int i = 0; i < n; ++i) {
cin >> dolls[i].first >> dolls[i].second;
}
// 按照開始時間對時間段進行排序
sort(dolls.begin(), dolls.end());
int maxWithDoll = 0, maxWithoutDoll = 0;
int start = dolls[0].first, end = dolls[0].second;
for (int i = 1; i < n; ++i) {
if (dolls[i].first <= end) { // 時間段重疊或連續
end = max(end, dolls[i].second);
} else { // 出現了無人澆花的時間段
maxWithoutDoll = max(maxWithoutDoll, dolls[i].first - end);
maxWithDoll = max(maxWithDoll, end - start);
start = dolls[i].first;
end = dolls[i].second;
}
}
maxWithDoll = max(maxWithDoll, end - start); // 更新最後一段時間
cout << maxWithDoll << " " << maxWithoutDoll << endl;
return 0;
}
L2-1 蕾米莉亞巡邏記
雙指標
include
include
include <unordered_map>
using namespace std;
int main() {
int n;
cin >> n;
vector
unordered_map<int, int> mp; // 用於記錄數字出現的次數
// 讀入資料
for(int i = 1; i <= n; i++) {
cin >> a[i];
}
int ans = 0; // 儲存最長不重複子陣列的長度
// 使用雙指標,l為左指標,r為右指標
for(int l = 1, r = 1; r <= n; r++) {
mp[a[r]]++; // 記錄當前數字出現的次數
// 如果當前數字出現次數大於1,則移動左指標直到該數字出現次數為1
while(mp[a[r]] > 1) {
mp[a[l]]--; // 左指標對應數字的次數減1
l++; // 左指標右移
}
// 更新最長不重複子陣列的長度
ans = max(ans, r - l + 1);
}
cout << ans << '\n';
return 0;
}
L2-2 月光糰子
棧
L2-3 你存在的價值
並查集 + 位運算
L2-4 夢想天生
BFS
L3-1 風神少女的祝福
拓撲排序 + 貪心
L3-2 七曜魔法使
最大流 + 質因數分解
L3-3 信仰是為了虛幻之人
樹鏈剖分 + 動態開點線段樹
基礎
語法
進位制轉換
第十三屆藍橋杯C++B組 A題 — 九進位制轉十進位制
include
include<math.h>
using namespace std;
int main()
{
cout << 2pow(9,3)+0pow(9,2)+2pow(9,1)+2pow(9,0) << endl;
return 0;
}
藍橋2406 字母數(簡單)
include
using namespace std;
// 判斷給定的整數n轉換為十六進位制表示時,所有位都大於等於10(即A到F)
bool judge(int n) {
while (n) {
int t = n % 16; // 獲取n的最低十六進位制位
if (t < 10) { // 如果這一位小於10,說明不滿足條件
return false;
}
n /= 16; // 去掉n的最低十六進位制位
}
return true; // 所有位都滿足條件,返回true
}
int main() {
for (int i = 2023; ; i++) { // 從2023開始迴圈,尋找滿足條件的最小整數
if (judge(i)) { // 如果找到滿足條件的整數
cout << i; // 輸出該整數
return 0; // 結束程式
}
}
}
B3620 x 進位制轉 10 進位制
include // 僅包含必要的標頭檔案
using namespace std;
// 宣告全域性變數
int x, a[105]; // x表示輸入的進位制,a陣列用於儲存轉換後的每一位數字
string S; // S用於儲存輸入的字串表示的數字
// char轉數碼函式,將字元轉換為對應的整數值
int charToInt(char c) {
if ('0' <= c && c <= '9') return c - '0'; // 處理數字字元
return c - 'A' + 10; // 處理字母字元,轉換為10~35的數字
}
int main() {
cin >> x >> S; // 輸入進位制和字串
int len = S.size(); // 獲取字串長度
// 逆序處理字串,將其轉換為整數陣列
for (int i = len - 1; i >= 0; i--)
a[len - 1 - i] = charToInt(S[i]);
int ans = 0, w = 1; // ans用於儲存最終結果,w為權值,初始為1
for (int i = 0; i < len; i++) { // 遍歷每一位,計算其對應的十進位制值
ans += w * a[i];
w *= x; // 權值隨著位數增加而增加
}
cout << ans; // 輸出轉換後的十進位制數
return 0;
}
思維
T419963 Light 的有序排列
校賽 02-B
題目描述:將一個排列切割成若干段,可進行翻轉,重新組合變成一個有序排列,統計最少的切割次數。
include
include // 提供abs函式
using namespace std;
const int N = 1e6 + 10; // 定義常量N為陣列大小上限
int n, a[N], res; // n為陣列長度,a為陣列,res為結果
int main() {
// 提高cin和cout效率的設定
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n; // 輸入陣列長度
for (int i = 1; i <= n; i++) {
cin >> a[i]; // 輸入陣列元素
}
// 遍歷陣列,計算相鄰元素差的絕對值大於1的情況數量
for (int i = 1; i < n; i++) {
res += (abs(a[i] - a[i + 1]) > 1); // 如果差的絕對值大於1,則累加到結果中
}
cout << res << '\n';
return 0;
}
模擬
基礎
第十三屆藍橋杯C++B組 C題 — 刷題統計
include
using namespace std;
int main() {
long long a, b, n; // 使用long long型別儲存大整數
cin >> a >> b >> n; // 輸入工作日每天消耗量a,週末每天消耗量b,以及總量n
long long weekCost = a * 5 + b * 2; // 計算一週總消耗量
long long ans = 0; // 初始化答案變數
ans += (n / weekCost) * 7; // 先計算總量可以支援完整週的數量,並轉換為天數
n %= weekCost; // 計算剩餘量
// 逐天減去消耗量,直到剩餘量不足以支援一天
for (int i = 1; n > 0 && i <= 7; ++i) {
if (i <= 5) {
n -= a; // 工作日消耗
} else {
n -= b; // 週末消耗
}
ans++; // 每迴圈一次,表示多支援了一天
}
cout << ans; // 輸出最終可以支援的天數
return 0;
}
藍橋2407 列名
include
using namespace std;
int main() {
int t = 26 + 26 * 26; // 初始值
bool found = false; // 用來標記是否找到符合條件的情況
for (int i = 65; i <= 90 && !found; i++) {
for (int j = 65; j <= 90 && !found; j++) {
for (int k = 65; k <= 90 && !found; k++) {
t++;
if (t == 2022) {
cout << char(i) << char(j) << char(k) << endl; // 列印字元而不是"ijk"
found = true; // 找到後設定found為true,以退出所有迴圈
}
}
}
}
return 0;
}
P8597 [藍橋杯 2013 省 B] 翻硬幣
include // 引入IO流庫
using namespace std;
string a, b;
int main() {
cin >> a >> b; // 輸入兩個字串
int l = a.size(), s = 0; // l 為字串長度,s 為翻轉次數
for(int i = 0; i < l; i++) {
if(a[i] != b[i]) { // 當字元不相同時
a[i] = a[i] == 'o' ? '' : 'o'; // 翻轉當前字元
a[i + 1] = a[i + 1] == 'o' ? '' : 'o'; // 翻轉下一個字元,不檢查邊界
s++; // 翻轉次數加一
}
}
cout << s << endl; // 輸出翻轉次數
return 0;
}
模擬+列舉
P1003 [NOIP2011 提高組] 鋪地毯
普及−
include
using namespace std;
const int MAXN = 10005; // 陣列最大長度
// 定義四個陣列,分別儲存每個矩形的左下角橫座標、縱座標、寬度和高度
int a[MAXN], b[MAXN], g[MAXN], k[MAXN];
int main() {
int n, x, y; // n為矩形的數量,x和y為查詢點的座標
cin >> n;
for(int i = 0; i < n; i++) {
cin >> a[i] >> b[i] >> g[i] >> k[i];
}
cin >> x >> y;
int ans = -1;
for(int i = n - 1; i >= 0; i--) {
// 從後向前遍歷所有矩形,確保找到的是最上層的矩形
// 判斷點(x, y)是否位於矩形i內
if(x >= a[i] && y >= b[i] && x <= a[i] + g[i] && y <= b[i] + k[i]) {
ans = i + 1; // 如果是,更新答案為矩形的編號(編號從1開始)
break;
}
}
cout << ans << endl;
return 0;
}
P1008 [NOIP1998 普及組] 三連擊
普及−
include
include
using namespace std;
// 檢查三個數是否按1:2:3的比例
bool check(int a, int b, int c) {
return 2 * a == b && 3 * a == c;
}
int main()
{ int nums[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // 最佳化:直接從第一個排列開始,避免了初始排序的開銷
sort(nums, nums + 9); // 確保陣列是按升序排列的,對於初始定義的陣列,這步可以省略
// 生成並遍歷1到9的所有排列
do {
// 將排列分成三個三位數
int a = nums[0] * 100 + nums[1] * 10 + nums[2];
int b = nums[3] * 100 + nums[4] * 10 + nums[5];
int c = nums[6] * 100 + nums[7] * 10 + nums[8]; // 檢查是否滿足1:2:3的比例,如果滿足,則輸出這三個三位數
if (check(a, b, c)) {
cout << a << " " << b << " " << c << endl;
}
} while (next_permutation(nums, nums + 9)); // 使用next_permutation生成下一個排列
return 0;
}
P1014 [NOIP1999 普及組] Cantor 表
普及−
include
using namespace std;
int main()
{
int n, k = 1;
cin >> n; // 讀取輸入的數字
while (n > k) {
n = n - k;
k++;
}
if (k % 2 == 0) {
cout << n << "/" << (k + 1 - n);
}
else {
cout << k + 1 - n << "/" << n;
}
return 0;
}
模擬+貪心
P1007 獨木橋
普及/提高−
include
include
include
using namespace std;
const int size = 5005;
int a[size];
int main()
{
int L, N;
cin >> L >> N; // 輸入橋的長度和人數
if (!N) { // 如果沒有人,則最短和最長時間都是0
cout << "0 0" << endl;
return 0;
}
for (int i = 1; i <= N; i++) cin >> a[i]; // 輸入每個人的起始位置
sort(a + 1, a + N + 1); // 對人的位置進行排序,以便後續計算
int max_time = 0, min_time = 0;
for (int i = 1; i <= N; i++) {
// 計算最短時間:找到每個人到達橋的兩端的最短距離中的最大值
min_time = max(min_time, min(a[i], L + 1 - a[i]));
}
// 計算最長時間:考慮最遠端的兩個人到達對岸的時間(排序的好處)
max_time = max(L + 1 - a[1], a[N]);
cout << min_time << ' ' << max_time << endl;
return 0;
}
排序
P1177 【模板】排序
普及−
include
include
include // 用於呼叫sort函式
using namespace std;
int main() {
int N;
cin >> N; // 表示需要排序的數的個數
vector
// 迴圈讀入N個數到向量arr中
for(int i = 0; i < N; ++i) {
cin >> arr[i];
}
sort(arr.begin(), arr.end()); // 從小到大排序
// 使用範圍式for迴圈輸出排序後的陣列,簡化程式碼
for(int i = 0; i < N; ++i) {
cout << arr[i];
if(i < N - 1) cout << " "; // 數字之間用空格隔開,最後一個數字後不加空格
}
cout << endl; // 換行
return 0;
}
列舉
第十四屆藍橋杯C++B組 A: 日期統計
//還可以字串 見後
include
include
include // 包含 find 函式
using namespace std;
int main() {
vector
};
int daysInMonth[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int ans = 0; // 記錄符合條件的子序列數量
// 2023年固定部分
vector
// 遍歷所有月份和天陣列合
for (int month = 1; month <= 12; month++) {
for (int day = 1; day <= daysInMonth[month]; day++) {
// 構造完整日期子序列:YYYYMMDD
vector
yearSeq[0], yearSeq[1], yearSeq[2], yearSeq[3],
month / 10, month % 10, day / 10, day % 10
};
// 在 array 中搜尋日期子序列
auto k = array.begin(); // 使用迭代器進行元素遍歷
for (int d:dateSeq) {
k = find(k, array.end(), d);
if (k == array.end()) break;
k++; // 移動到下一個元素以繼續搜尋
}
if (k != array.end()) {
ans++; // 找到日期,增加計數
}
}
}
cout << ans << endl; // 列印找到的符合條件的子序列數量
return 0;
}
第十三屆藍橋杯C++B組 B題 — 順子日期
include
using namespace std;
// 定義每個月的天數,注意閏年2月為29天
int day[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
// 檢查陣列中的某個部分是否形成順子
bool check(int a[]) {
for (int i = 3; i <= 5; i++) {
// 檢查連續三個數字是否形成順子(注意順子的定義是遞增的,如123, 456)
if (a[i] == a[i + 1] - 1 && a[i + 1] == a[i + 2] - 1) {
return true;
}
}
return false;
}
int main() {
// 初始日期設定為2022年,因為我們只考慮2022年
int a[8] = {2, 0, 2, 2}; // 年份2022固定
int res = 0; // 用於計算滿足條件的天數
// 遍歷每個月
for (int i = 1; i <= 12; i++) {
// 設定月份,注意十位和個位是分開的
a[4] = i / 10 % 10; // 十位
a[5] = i % 10; // 個位
// 遍歷每天
for (int j = 1; j <= day[i]; j++) {
// 設定日期,注意十位和個位是分開的
a[6] = j / 10 % 10; // 十位
a[7] = j % 10; // 個位
// 檢查是否形成順子
if (check(a)) {
res++; // 如果形成順子,則結果加1
}
}
}
cout << res; // 輸出滿足條件的天數總數
return 0;
}
藍橋2409 大乘積
include
using namespace std;
// 定義一個包含30個元素的陣列
int a[30] = {99, 22, 51, 63, 72, 61, 20, 88, 40, 21, 63, 30, 11, 18, 99, 12, 93, 16, 7, 53, 64, 9, 28, 84, 34, 96, 52, 82, 51, 77};
int main() {
int res = 0;
// 外層迴圈遍歷陣列中的每一個元素
for (int i = 0; i < 30; i++) {
// 內層迴圈遍歷當前元素之後的每一個元素,以形成唯一的元素對
for (int j = i + 1; j < 30; j++) {
if (a[i] * a[j] >= 2022) {
res++;
}
}
}
cout << res << endl;
return 0;
}
T409142 「YAC Round 1」三妖精SAY WA!!!
校賽 01-A
題目描述:求出陣列中 小於等於 上界 m 的最大三數之和。
include
using namespace std;
const int N = 110; // 定義陣列大小常量
int a[N], n, m, res; // 定義陣列、陣列大小、目標和、結果變數
int main() {
// 輸入陣列大小n和目標和m
cin >> n >> m;
// 輸入陣列元素
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
// 三重迴圈列舉所有可能的三個數的組合
for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
for (int k = j + 1; k <= n; k++) {
int sum = a[i] + a[j] + a[k];
if (sum <= m) {
res = max(res, sum);
}
}
}
}
cout << res << '\n';
return 0;
}
T422762 愛麗絲的 Sweet Magic
校賽 03-A
題目描述:給定一個陣列 a,對其中某一個元素 +1,使得 乘積 儘可能大
include
include
include // 提供max函式
using namespace std;
typedef long long ll; // 定義一個長整型別名ll
int main() {
// 提高cin和cout效率的設定
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector
for (int i = 1; i <= n; i++) {
cin >> a[i]; // 讀入陣列元素
}
ll res = 0; // 初始化結果為0
// 遍歷陣列,尋找最大乘積
for (int i = 1; i <= n; i++) {
ll prod = a[i] + 1; // 將當前元素加1
// 計算除了當前元素外其他元素的乘積
for (int j = 1; j <= n; j++) {
if (i != j) prod *= a[j];
}
// 更新最大乘積
res = max(res, prod);
}
cout << res << '\n';
}
return 0;
}
B: 01 串的熵
第十四屆藍橋杯C++B組
include
include
include
using namespace std;
const int total = 23333333;
const double H = 11625907.5798;
int main() {
// 由於函式是關於 i 的對稱函式,只需搜尋前一半的 i 值
for (int i = 0; i <= total / 2; i++) {
double ans = 0;
// 計算當前 i 對應的 ans 值
if (i > 0) { // 避免對 0 取對數
ans -= 1.0 * i * i / total * log2(1.0 * i / total);
}
if (total - i > 0) { // 同樣避免對 0 取對數
ans -= 1.0 * (total - i) * (total - i) / total * log2(1.0 * (total - i) / total);
}
// 如果 ans 與 H 的差值小於 1e-4,則找到了所需的 i
if (abs(ans - H) < 1e-4) {
cout << i << endl;
return 0;
}
}
return 0;
}
搜尋
DFS(深度優先搜尋)
T422770 迷途竹林的月色(模板)
第十四屆藍橋杯C++B組 D: 飛機降落
include
include
using namespace std;
const int N = 10; // 定義常量N,表示任務的最大數量
int n; // n表示任務的數量
bool st[N]; // st陣列用於標記任務是否已被訪問
bool flag = false; // flag標記是否找到了有效的順序
int t[N], d[N], l[N]; // t、d、l分別表示任務的開始時間、截止時間和持續時間
// 深度優先搜尋函式,u表示當前處理的任務編號,last表示上一個任務完成的時間
void dfs(int u, int last) {
if (flag) return; // 如果已經找到有效順序,直接返回
if (u == n) { // 如果所有任務都已處理,標記找到有效順序並返回
flag = true;
return;
}
for (int i = 0; i < n; i++) { // 遍歷所有任務
if (!st[i] && t[i] + d[i] >= last) { //如果任務 i 未被訪問(st[i] 為 false)且其開始時間加上持續時間不早於上一個任務的完成時間(last),這意味著任務 i 可以緊接著上一個任務執行
st[i] = true; // 標記任務i為已訪問
if (t[i] > last) dfs(u + 1, t[i] + l[i]);
//如果任務i的開始時間晚於上一個任務的完成時間,則從任務i的結束時間(考慮了它的延時l[i])作為新的last值繼續搜尋。
else dfs(u + 1, last + l[i]);
//如果任務i可以立即開始(即它的開始時間不晚於上一個任務的結束時間),則從上一個任務的結束時間加上當前任務的延時l[i]作為新的last值繼續搜尋。
st[i] = false; // 回溯,取消標記任務i
}
}
}
int main() {
int T; // T表示測試用例的數量
cin >> T;
while (T--) {
cin >> n; // 輸入任務的數量
for (int i = 0; i < n; i++) cin >> t[i] >> d[i] >> l[i]; // 輸入每個任務的開始時間、盤旋時間和持續時間
fill(st, st + N, false); // 使用fill函式初始化st陣列為false
flag = false; // 初始化flag為false
dfs(0, 0); // 從第0個任務和時間0開始深度優先搜尋
if (flag) cout << "YES" << endl; // 如果找到有效順序,輸出YES
else cout << "NO" << endl; // 否則輸出NO
}
return 0;
}
第十四屆藍橋杯C++B組 F: 島嶼個數
include
include
using namespace std;
// 方向陣列,用於表示島嶼上下左右的探索
int deltaOfIsland[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
// 方向陣列,用於表示海洋的8個方向探索
int deltaOfSea[8][2] = {{-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}};
int ans = 0; // 儲存最終的島嶼數量
// 用於探索島嶼的深度優先搜尋函式
void DFS_Island(vector<vector
data[r][c] = 'N'; // 標記當前位置已經訪問
for (int i = 0; i < 4; ++i) {
int newR = r + deltaOfIsland[i][0];
int newC = c + deltaOfIsland[i][1];
if (newR >= 0 && newR < m && newC >= 0 && newC < n) {
if (data[newR][newC] == '1') {
DFS_Island(data, newR, newC, m, n); // 遞迴訪問相鄰的島嶼
}
}
}
}
// 用於探索海洋的深度優先搜尋函式
void DFS_Sea(vector<vector
data[r][c] = 'N'; // 標記當前位置已經訪問
for (int i = 0; i < 8; ++i) {
int newR = r + deltaOfSea[i][0];
int newC = c + deltaOfSea[i][1];
if (newR >= 0 && newR < m && newC >= 0 && newC < n) {
if (data[newR][newC] == '1') {
DFS_Island(data, newR, newC, m, n); // 如果遇到島嶼,則進入DFS_Island
++ans; // 島嶼數量加1
}
else if (data[newR][newC] == '0') {
DFS_Sea(data, newR, newC, m, n); // 如果遇到海洋,則繼續探索
}
}
}
}
int main() {
int t;
cin >> t;
vector<vector<vector
for (int i = 0; i < t; ++i) {
int m, n;
cin >> m >> n;
vector<vector
for (int r = 1; r <= m; ++r) {
for (int c = 1; c <= n; ++c) {
cin >> data[r][c]; // 讀入原始地圖資料
}
}
datas.push_back(data);
}
for (int i = 0; i < t; ++i) {
vector<vector<char>> &data = datas[i];
int m = data.size();
int n = data[0].size();
DFS_Sea(data, 0, 0, m, n); // 從(0,0)開始探索整個地圖
cout << ans << endl;
ans = 0; // 重置島嶼數量,為下一個測試用例做準備
}
return 0;
}
BFS(廣度優先搜尋)
小紅走矩陣
include
include
include
using namespace std;
// 用來表示方向的陣列,分別對應上、下、左、右
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};
// 檢查新位置是否有效
bool isValid(int x, int y, int n, int m) {
return x >= 0 && x < n && y >= 0 && y < m;
}
int bfs(vector
int n = matrix.size();
int m = matrix[0].size();
// 建立一個同樣大小的矩陣來記錄是否訪問過
vector<vector
// 使用佇列來進行BFS
queue<pair<int, pair<int, int>>> q; // 佇列中儲存步數和座標
q.push({0, {0, 0}}); // 從左上角開始
visited[0][0] = true; // 標記為已訪問
while (!q.empty()) {
auto front = q.front();
q.pop();
int steps = front.first;
int x = front.second.first;
int y = front.second.second;
// 如果到達右下角,返回步數
if (x == n-1 && y == m-1) return steps;
// 探索四個方向
for (int i = 0; i < 4; ++i) {
int newX = x + dx[i];
int newY = y + dy[i];
// 如果新位置有效且未訪問過,且字元不同
if (isValid(newX, newY, n, m) &&
!visited[newX][newY] &&
matrix[newX][newY] != matrix[x][y]) {
visited[newX][newY] = true; // 標記為已訪問
q.push({steps + 1, {newX, newY}}); // 加入佇列
}
}
}
// 如果佇列為空,說明無法到達右下角
return -1;
}
int main() {
int n, m;
cin >> n >> m;
vector
for (int i = 0; i < n; ++i) {
cin >> matrix[i];
}
cout << bfs(matrix) << endl;
return 0;
}
貪心
P8637 [藍橋杯 2016 省 B] 交換瓶子
include // 引入IO流庫
using namespace std; // 使用標準名稱空間
const int MAXN = 1e6 + 10;
int num, ans = 0;
int a[10010];
int main() {
int n;
cin >> n; // 輸入陣列長度
for (int i = 1; i <= n; i++) {
cin >> a[i]; // 輸入陣列元素
}
// 遍歷陣列,進行位置交換
for (int j = 1; j <= n; j++) {
while (a[j] != j) { // 當前位置不正確時,進行交換
swap(a[j], a[a[j]]);
ans++; // 記錄交換次數
}
}
cout << ans << endl; // 輸出交換次數
return 0;
}
T409120 「YAC Round 1」夜雀之歌
校賽01-B
題目描述:構造一個長度為n 的 01 字串,滿足 恰好有 p 個不處於字串兩端的 0 兩邊是1,且輸出字典序最小的構造方案。
include
using namespace std;
// 定義快速輸入輸出流的宏
define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
int main() {
ios; // 應用快速輸入輸出流最佳化
int T, n, p;
cin >> T;
while (T--) {
cin >> n >> p;
// 判斷是否可以構造滿足條件的字串
if (n < 2 * p + 1) {
cout << -1 << '\n'; // 如果不能構造,則輸出-1
continue;
}
string res; // 定義結果字串
// 構造多餘的0
for (int i = 2 * p + 1; i < n; i++) res += "0";
// 構造p個滿足條件的"10"
for (int i = 1; i <= p; i++) res += "10";
// 最後再加一個1
res += "1";
cout << res << '\n'; 、
}
return 0;
}
遞推與遞迴
二分
雙指標
第十四屆藍橋杯C++B組 G: 子串簡寫
include // 包含輸入輸出流庫
using namespace std;
int K;
long long ans = 0, c1_sum = 0; // ans用於儲存最終答案,c1_sum用於統計到目前為止遇到的c1字元數量
string S;
char c1, c2;
int main() {
cin >> K >> S >> c1 >> c2; // 輸入K值,字串S和字元c1、c2
// 遍歷字串S,從索引K-1開始,確保每次考慮的子串長度至少為K
for (int i = K - 1, j = 0; i < S.length(); i++, j++) {
if (S[j] == c1) c1_sum++; // 如果當前字元是c1,則增加c1的計數
if (S[i] == c2) ans += c1_sum; // 如果當前字元是c2,則將c1_sum加到答案上
}
cout << ans; // 輸出最終的答案
return 0;
}
T408863 魔法使的事,能叫偷嗎?
校賽01-D
題目描述:在序列中找到一個包含數字 1,2,3,……,m的最小長度的連續區間[l,r] 。若有多組解,輸出 l 最小的那 個。(資料保證一定有解)
include
include
using namespace std;
const int N = 1e6 + 10, M = 2010, inf = 0x3f3f3f3f; // 定義常量
int main(){
ios::sync_with_stdio(false); // 禁用stdio同步以加快cin和cout
cin.tie(nullptr); // 解除cin和cout的繫結,允許它們同時進行
cout.tie(nullptr); // 同上
int n, m;
cin >> n >> m; // 輸入陣列的長度和不同數字的目標數量
vector
for(int i = 1; i <= n; i++) cin >> a[i]; // 輸入陣列元素
// 雙指標法
int l = 1, r = 1; // 初始化左右指標
int diff = 1; // 當前不同數字的數量
int res = inf; // 最小區間的長度,初始化為無窮大
int res_l, res_r; // 記錄最小區間的左右端點
cnt[a[1]] = 1; // 初始化第一個數字的計數
// 遍歷陣列
while(l <= r && r <= n){
if(diff == m){ // 如果當前區間已經包含m個不同的數字
if(res > r - l + 1){ // 如果當前區間更小,則更新答案
res = r - l + 1;
res_l = l, res_r = r;
}
cnt[a[l]]--; // 左指標對應的數字計數減一
if(!cnt[a[l]]) diff--; // 如果該數字計數為0,不同數字數量減一
l++; // 左指標向右移動
}else{ // 如果當前區間不足m個不同的數字
r++; // 右指標向右移動
if(r > n) break; // 如果右指標超出陣列範圍,則退出迴圈
if(!cnt[a[r]]) diff++; // 如果新加入的數字是新的不同數字,則不同數字數量加一
cnt[a[r]]++; // 右指標對應的數字計數加一
}
}
// 如果找到了滿足條件的區間,則輸出區間的左右端點
if(res != inf){
cout << res_l << ' ' << res_r << '\n';
} else {
cout << "-1 -1\n"; // 否則輸出-1 -1,表示沒有找到滿足條件的區間
}
return 0;
}
字首和、差分與離散化
T408861 BBA
校賽01-C
題目描述:統計字串中 bba 型 子序列 個數,字串只包含小寫英文字元。
include
include
include
using namespace std;
typedef long long ll;
int main(){
ios::sync_with_stdio(false); // 禁用stdio同步以加快cin和cout
cin.tie(nullptr); // 解除cin和cout的繫結,允許它們同時進行
cout.tie(nullptr); // 同上
int n;
string s;
cin >> n >> s;
vector<ll> cnt(26, 0); // 使用vector代替陣列,初始化26個字母的計數為0
ll res = 0;
// 遍歷字串中的每個字元
for(int i = 0; i < n; i++){
// 對於每個字元,計算與其不同的字元所形成的對數
for(int j = 0; j < 26; j++){
if(j != s[i] - 'a'){
res += cnt[j] * (cnt[j] - 1) / 2; // 計算組合數並累加到結果中
}
}
// 更新當前字元的計數
cnt[s[i] - 'a']++;
}
cout << res << '\n';
return 0;
}
矩陣
include
include
using namespace std;
int main() {
int n, m, x;
cin >> n >> m >> x;
vector<vector
int sum = 0; // 所有元素之和
vector
vector
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
cin >> matrix[i][j];
sum += matrix[i][j]; // 計算總和
rowXor[i] ^= matrix[i][j]; // 更新行的異或和
colXor[j] ^= matrix[i][j]; // 更新列的異或和
}
}
if (sum != x) { // 檢查總和是否為x
cout << "wrong answer" << endl;
return 0;
}
int xorValue = rowXor[0]; // 假設第一行的異或和為標準
for (int i = 1; i < n; ++i) {
if (rowXor[i] != xorValue) { // 檢查每行異或和是否相等
cout << "wrong answer" << endl;
return 0;
}
}
for (int j = 0; j < m; ++j) {
if (colXor[j] != xorValue) { // 檢查每列異或和是否相等
cout << "wrong answer" << endl;
return 0;
}
}
cout << "accepted" << endl; // 所有條件都滿足
return 0;
}
線性表
二叉樹
集合
圖的基本應用
基礎數學
第十三屆藍橋杯C++B組 D題: 修剪灌木
include
include // 引入以使用max函式
using namespace std;
int main() {
int n;
cin >> n; // 輸入n
for (int i = 0; i < n; ++i) {
// 計算並列印i和n-i-1之間的最大值的兩倍
cout << max(i, n - i - 1) * 2;
cout << endl;
}
return 0;
}
第十四屆藍橋杯C++B組 C: 冶煉金屬
//也可以二分
include
include // 引入演算法庫,用於max和min函式
using namespace std;
int main() {
int n;
cin >> n;
int ansMin = 0, ansMax = 1e9; // 初始化最小值和最大值,假設最大值不超過10^9
for (int i = 0; i < n; ++i) { // 使用for迴圈替代while迴圈,使邏輯更清晰
int a, b;
cin >> a >> b; // 讀入每組的a和b值
// 根據給定的邏輯更新ansMin和ansMax(公式)
// ansMin為所有組中計算得到的最大的最小值
// ansMax為所有組中計算得到的最小的最大值
ansMin = max(a / (b + 1) + 1, ansMin);
ansMax = min(a / b, ansMax);
}
// 輸出滿足條件的最小值和最大值範圍
cout << ansMin << " " << ansMax << endl;
return 0;
}
T429116 「YAC Round 6」琪露諾的超級⑨拆分
入門
題目描述
定義飛階數字為:每一位都是 9 的,且位數為k 的倍數的正整數。給定多次詢問,每次詢問一個數字
n,判斷這個數字是否可以拆成若千個 k 階數字的和。
include
using namespace std;
typedef long long ll;
// 函式check用於檢查n是否能被k階的最大數整除
bool check(ll k, ll n) {
ll c = 0;
while (k--) c = c * 10 + 9; // 得到最小k階數字,實際上是k個9組成的數字
return n % c == 0; // 如果n能被c整除,則返回true,否則返回false
}
int main() {
// 加快IO操作
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int q; // q代表測試案例的數量
cin >> q;
while (q--) { // 迴圈處理所有測試案例
ll k, n; // k為階數,n為待檢查的數
cin >> k >> n;
// 輸出結果,如果n能被k階的最大數整除,則輸出"aya",否則輸出"baka"
cout << (check(k, n) ? "aya" : "baka") << '\n';
}
return 0;
}
樹
DP
P9242 [藍橋杯 2023 省 B] 接龍數列
Ai的首位數字恰好等於Ai−1的末位數字
include // 包含輸入輸出流庫
include // 包含string類庫
include // 包含演算法庫,提供max函式
using namespace std;
int n, m, i, dp[10];
string a; // 用字串儲存,便於運算
int main() {
ios::sync_with_stdio(false); // 關閉同步,加速cin和cout
cin.tie(nullptr); // 解綁cin和cout,進一步加速輸入輸出
cin >> n; // 輸入數字的數量
for (i = n; i--; ) {
cin >> a; // 輸入每個數字
// 更新以數字最後一位為結尾的最長序列的長度
// a[a.size()-1]-'0' 轉換字元為數字
// dp[a[0]-'0']+1 嘗試將當前數字作為序列的擴充套件
dp[a[a.size() - 1] - '0'] = max(dp[a[a.size() - 1] - '0'], dp[a[0] - '0'] + 1);
}
for (i = 0; i <= 9; i++) m = max(m, dp[i]); // 取最大值,即找到最長的由數字構成的序列
cout << n - m; // 輸出需要移除的最小數字數量
return 0; // 返回0表示程式正常結束
}
DP最短路(Dijkstra)
T409013 時間凍結
校賽 01-E
題目描述:N 個點,M 條無向邊,可以最多 選擇 K 條邊將其長度縮減為原先長度的一半,求1到 N 的最短距離(邊的長度一定是偶數,所以不用擔心出現浮點數情況)。
include
include
include
include
using namespace std;
const int N = 60, M = 2010, inf = 0x3f3f3f3f; // 定義最大節點數、最大邊數和無窮大表示的常量
// 鏈式前向星儲存圖的結構
int h[N], e[M], ne[M], w[M], idx;
// 新增邊的函式,a和b是邊的兩個節點,c是邊的權重
void add(int a, int b, int c) {
e[++idx] = b; // 邊的目標節點
ne[idx] = h[a]; // 當前邊的下一條邊
w[idx] = c; // 邊的權重
h[a] = idx; // 節點a的第一條邊
}
int n, m, K;
int dist[N][N]; // dist[v][cnt] 表示使用了cnt張符卡狀態下1到v的最短距離
bool st[N][N]; // st[v][cnt] 表示狀態(v, cnt)是否已經在最短路徑樹中
// 定義節點結構體用於儲存優先佇列中的資訊
struct Node {
int d, u, cnt;
// 過載小於運算子,便於優先佇列進行比較,優先佇列預設是大根堆,所以這裡用大於號
bool operator < (const Node &W) const {
return d > W.d;
}
};
// 堆最佳化的dijkstra演算法
void dijkstra() {
memset(dist, 0x3f, sizeof dist); // 初始化所有距離為無窮大
dist[1][0] = 0; // 起點到自己的距離為0
priority_queue
q.push({0, 1, 0}); // 將起點加入優先佇列
while (q.size()) {
Node t = q.top(); // 取出佇列頂部元素
q.pop(); // 彈出佇列頂部元素
int d = t.d, u = t.u, cnt = t.cnt;
if (st[u][cnt]) continue; // 如果該狀態已經處理過,跳過
st[u][cnt] = true; // 標記狀態為已處理
for (int i = h[u]; i; i = ne[i]) {
int v = e[i], c = w[i];
// 不使用符卡的情況
if (dist[v][cnt] > d + c) {
dist[v][cnt] = d + c;
q.push({dist[v][cnt], v, cnt});
}
// 使用符卡的情況
if (cnt < K && dist[v][cnt + 1] > d + (c >> 1)) {
dist[v][cnt + 1] = d + (c >> 1);
q.push({dist[v][cnt + 1], v, cnt + 1});
}
}
}
}
int main() {
ios::sync_with_stdio(false); // 禁用同步流,提高cin和cout效率
cin.tie(0); // 解綁cin和cout的繫結
cout.tie(0); // 解綁cout和cerr的繫結
cin >> n >> m >> K; // 輸入節點數、邊數和符卡數
while (m--) {
int u, v, c;
cin >> u >> v >> c; // 輸入邊的資訊
add(u, v, c); // 新增邊到圖中
add(v, u, c); // 無向圖,需要新增兩條邊
}
dijkstra(); // 執行dijkstra演算法
int res = inf; // 初始化結果為無窮大
// 遍歷所有可能的符卡使用次數,找到最短距離
for (int i = 0; i <= K; i++) {
res = min(res, dist[n][i]);
}
cout << res << endl;
return 0;
}
最小生成樹
連通性問題
字首和、差分與離散化,常見最佳化技巧,分治與倍增
字串
基礎
P1000 超級瑪麗遊戲
入門
include
using namespace std;
int main()
{
cout<<R"( ******** ************ ####....#. #..###.....##.... ###.......###### ### ### ........... #...# #...# ######### #.#.# #.#.# ########## #.#.# #.#.# ...#..###.... #...# #...# ....******##..... ### ### .... *****.... #### #### ###### ###### ############################################################## #...#......#.##...#......#.##...#......#.##------------------# ###########################################------------------# #..#....#....##..#....#....##..#....#....##################### ########################################## #----------# #.....#......##.....#......##.....#......# #----------# ########################################## #----------# #.#..#....#..##.#..#....#..##.#..#....#..# #----------# ########################################## ############ )"<< endl;
}
A: 日期統計
第十四屆藍橋杯C++B組
include
include
using namespace std;
const int NUMBERS[100] = {
5, 6, 8, 6, 9, 1, 6, 1, 2, 4, 9, 1, 9, 8, 2, 3, 6, 4, 7, 7,
5, 9, 5, 0, 3, 8, 7, 5, 8, 1, 5, 8, 6, 1, 8, 3, 0, 3, 7, 9,
2, 7, 0, 5, 8, 8, 5, 7, 0, 9, 9, 1, 9, 4, 4, 6, 8, 6, 3, 3,
8, 5, 1, 6, 3, 4, 6, 7, 0, 7, 8, 2, 7, 6, 8, 9, 5, 6, 5, 6,
1, 4, 0, 1, 0, 0, 9, 4, 8, 0, 9, 1, 2, 8, 5, 0, 2, 5, 3, 3
};
const int DAYS[13] = {
0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
int main() {
int ans = 0; // 用於統計符合條件的日期數量
// 遍歷每個月的每一天
for (int month = 1; month <= 12; month++) {
for (int day = 1; day <= DAYS[month]; day++) {
string date = "2023"; // 初始化日期字串,年份固定為2023
// 如果月份是個位數,前面補0
date += (month < 10) ? "0" : "";
date += to_string(month); // 新增月份
// 如果日期是個位數,前面補0
date += (day < 10) ? "0" : "";
date += to_string(day); // 新增日期
int k = 0; // 用於記錄匹配的數字數量
// 遍歷NUMBERS陣列,查詢與日期字串匹配的數字序列
for (int l = 0; l < 100 && k < 8; l++) {
if (NUMBERS[l] == date[k] - '0') k++; //檢查NUMBERS陣列當前的元素是否與date字串中當前位置的字元匹配。由於date[k]是一個字元,所以需要透過減去'0'來獲取其對應的整數值。
}
// 如果匹配的數字數量達到8或以上,計數加1
if (k >= 8) ans++;
}
}
cout << ans << endl; // 輸出符合條件的日期數量
return 0;
}
字串+模擬
T419870 輝夜的最強密碼
校賽 02-A
輸入多個字串,判斷每個字串是否滿足指定條件。滿足條件輸出“True ”;否則輸出“False ”。
include
include
include
include // 提供islower, isupper, isdigit等函式
using namespace std;
int main() {
int T;
cin >> T;
while (T--) {
string s;
cin >> s;
int n = static_cast
// 條件1:如果字串長度小於7,直接輸出False
if (n < 7) {
cout << "False\n";
continue;
}
// 條件2:檢查是否包含小寫字母、大寫字母和數字
vector
for (auto &ch : s) {
if (islower(ch)) flag[0] = true;
else if (isupper(ch)) flag[1] = true;
else if (isdigit(ch)) flag[2] = true;
}
if (!flag[0] || !flag[1] || !flag[2]) {
cout << "False\n";
continue;
}
// 條件3:檢查是否存在連續的數字
bool ok = true;
for (int i = 0; i < n - 1; i++) {
if (isdigit(s[i]) && isdigit(s[i + 1])) {
ok = false;
break;
}
}
cout << (ok ? "True" : "False") << '\n';
}
return 0;
}
字串+高精度
P1601 A+B Problem(高精)
普及−
include
include
include // 用於reverse函式
using namespace std;
// 高精度加法函式,接受兩個字串形式的非負整數a和b,返回它們的和 string highPrecisionAdd(string a, string b) {
string result; // 儲存最終結果
reverse(a.begin(), a.end()); // 將字串a反轉,以便從最低位開始相加
reverse(b.begin(), b.end()); // 將字串b反轉
int carry = 0; // 進位
for(size_t i = 0;
i < max(a.size(), b.size()) || carry; ++i) {
if(i < a.size()) carry += a[i] - '0'; // 如果a的當前位存在,則加到carry上
if(i < b.size()) carry += b[i] - '0'; // 如果b的當前位存在,則加到carry上
result.push_back(carry % 10 + '0'); // 計算當前位的結果,並轉換為字元後加到result
carry /= 10; // 計算新的進位
}
reverse(result.begin(), result.end()); // 將結果反轉回正確的順序
return result; // 返回結果字串 }
int main()
{
string a, b;
cin >> a >> b; // 分兩行輸入兩個非負整數a和b
cout << highPrecisionAdd(a, b) << endl;
return 0;
}
進階搜尋
並查集
P3367 【模板】並查集
普及/提高−
include
using namespace std;
const int MAXN = 10010; // 定義最大的節點數
int f[MAXN]; // f[i] 表示節點i的集合名(或父節點)
// 查詢並返回元素k的根節點,同時進行路徑壓縮 int find(int k) {
if (f[k] != k) { //檢查當前元素k是否是自己的父節點。
//如果不是,說明k不是代表元素,需要遞迴地向上查詢。
f[k] = find(f[k]); // 路徑壓縮
}
return f[k];
}
int main() {
int n, m, p1, p2, p3;
cin >> n >> m; // 輸入節點總數和操作總數
// 初始化,每個節點的父節點設定為自己
for (int i = 1; i <= n; i++) {
f[i] = i;
}
// 處理m個操作
for (int i = 0; i < m; i++) {
cin >> p1 >> p2 >> p3; // 輸入操作型別和操作涉及的節點
if (p1 == 1) { // 如果是型別1的操作,表示p3打贏了p2,將p2的根節點父親設為p3的根節點
f[find(p2)] = find(p3);
} else {
// 如果是型別2的操作,查詢p2和p3是否屬於同一個集合
if (find(p2) == find(p3)) {
cout << "Y\n"; // 是一夥的
} else {
cout << "N\n"; // 不是一夥的
}
}
}
return 0;
}
二叉堆與樹狀陣列
線段樹
線段樹的進階用法
線性狀態動態規劃
區間與環形動態規劃
樹與圖上的動態規劃
狀態壓縮動態規劃
動態規劃的設計與最佳化
進階數論
組合數學與計數
機率與統計
基礎線性代數
未分類