比賽地址c++
題目連接
⭐數組
題目:
給出一個\(01\)序列,有2種操做:1.將某個位置取反;2.詢問\(01\)序列中第\(k\)大的數函數
解析:
顯然維護1的數目便可spa
#include<bits/stdc++.h> using namespace std; /*===========================================*/ int ones = 0; const int maxn = 1e5 + 5; int dat[maxn]; int main() { int n, q, a, b; scanf("%d%d", &n, &q); for (int i = 0; i < n; ++i) { scanf("%d", &dat[i]); ones += dat[i]; }; while (q--) { scanf("%d%d", &a, &b); if (a == 1) { --b; if (dat[b]) --ones; else ++ones; dat[b] = 1 - dat[b]; } else { printf("%d\n", ones >= b); } } }
題目連接
⭐⭐code
題目:
給出一張圖,由\(n(n\le100)\)行(行從1開始編號),\(10^6+1\)列組成(列從0開始編號),在所給矩陣的每一行存在一個障礙,如今能夠花費\(v\)使得障礙水平移動,\(u\)使得障礙豎直移動,問若要從\((1,0)\)能夠到達\((n,10^6+1)\),最小花費是多少?
(題目所給障礙物水平移動範圍不包含兩端)blog
解析:
因爲水平移動範圍不包含兩端,因此不會出現上下封閉的狀況,那麼只有一種狀況下沒法到達,即全部障礙造成一條連續線段,將圖分割成左右兩部分,在這樣的狀況下,分如下兩種狀況進行討論:遞歸
#include<bits/stdc++.h> using namespace std; /*===========================================*/ int ones = 0; const int maxn = 105; int ob[maxn]; int main() { int T; int n, u, v; scanf("%d", &T); while (T--) { bool left = true; scanf("%d%d%d", &n, &u, &v); for (int i = 0; i < n; ++i) scanf("%d", &ob[i]); int last = 0; bool equ = true, line = true; for (int i = 1; i < n; ++i) { if (abs(ob[i] - ob[i - 1]) > 1) { line = false; break; } if (ob[i] != ob[i - 1]) equ = false; } if (line) { if (equ) printf("%d", min(2 * v, u + v)); else printf("%d", min(u, v)); } else printf("%d", 0); printf("\n"); } }
題目連接
⭐⭐⭐遊戲
題目:
給出\(n\)個蹦牀,每一個蹦牀有一個強度\(S_i\),若是身處\(i\)蹦牀,會跳躍至\(i+S_i\)處,且每次蹦牀被踩壓後,強度會\(-1\),但至多減至1,如今能夠從任意位置起跳,每次跳躍直到無蹦牀能夠踩壓爲止,問將全部蹦牀強度降至\(1\),所最少須要的遊戲次數ci
解析:get
注意:
#include<bits/stdc++.h> using namespace std; const int maxn = 5e3 + 5; int dat[maxn]; int t[maxn]; long long ret; int main() { int T,n; scanf("%d", &T); while (T--) { ret = 0; scanf("%d", &n); for (int i = 0; i < n; ++i) scanf("%d", &dat[i]); memset(t, 0, sizeof(t)); for (int i = 0; i < n; ++i) { int x = max(0, dat[i] - 1 - t[i]); ret += x; int end = min(n - 1, i + dat[i]); for (int j = i + 2; j <= end; ++j) ++t[j]; t[i + 1] += max(t[i] - dat[i] + 1, 0); } printf("%lld\n", ret); } }
題目連接
⭐⭐⭐
題目:
規定若是\(u\&v=v\),則\(u\)可達\(u+v\),如今給出\(u,v\),問是否能夠從\(u\)到\(v\)
解析:
附:
題目連接
⭐⭐⭐⭐⭐
題目:
規定\(Fib-tree\)必須知足如下條件
如今給出樹的邊,問是不是一個\(Fib-tree\)
解析:
首先對頂點數進行斷定是否爲\(Fibonacci數\)
如若這個樹能夠分割成兩個子\(Fib-tree\),則必定能確定兩個子樹的頂點數爲\(fib[k-1],fib[k-2]\),同時也能夠證實,若是存在多條(最多兩條,由樹的定義可知)能夠分割的邊,則消除任意一條可行邊不會影響結果
證實:若是存在兩條邊分割子樹頂點數爲\(fib[k-1],fib[k-2]\),若是使用某一條可行邊將其分割,另外一條可行邊必定是在\(fib[k-1]\)對應的子樹中,會將\(fib[k-1]\)分割爲\(fib[k-2],fib[k-3]\),因此兩條邊是等價的
這樣的狀況下,構建一個\(getSize\)函數獲取以某個點爲根,子樹的大小,若是子樹大小爲\(fib[k-1]\)或者\(fib[k-2]\)則考慮分割這條邊,而後進行遞歸性的處理便可
#include <bits/stdc++.h> using namespace std; const int maxn = 2e5 + 5; vector<int> fib; typedef pair<int, bool> P; vector<P> e[maxn]; int siz[maxn]; int n; void no() { printf("NO"); exit(0); } void getSize(int u, int fa) { siz[u] = 1; for (auto& i : e[u]) { if (i.second || i.first == fa) continue; getSize(i.first, u); siz[u] += siz[i.first]; } } void cutEdge(int u, int fa, int k, int& pu, int& pv, int& kd) { for (auto& i : e[u]) { if (pu) return; if (i.second || i.first == fa) continue; if (siz[i.first] == fib[k - 1] || siz[i.first] == fib[k - 2]) { pu = u, pv = i.first; kd = siz[i.first] == fib[k - 1] ? k - 1 : k - 2; return; } cutEdge(i.first, u, k, pu, pv, kd); } } void Check(int u, int k) { if (k <= 1) return; getSize(u, 0); int pu = 0, pv = 0, kd = 0; cutEdge(u, 0, k, pu, pv, kd); if (!pu) no(); for (auto& i : e[pu]) if (i.first == pv) i.second = true; for (auto& i : e[pv]) if (i.first == pu) i.second = true; Check(pv, kd); Check(pu, 2 * k - 3 - kd); } int main() { int u, v; scanf("%d", &n); fib.push_back(1), fib.push_back(1);; while (fib.back() < n) fib.push_back(fib[fib.size() - 1] + fib[fib.size() - 2]); for (int i = 1; i < n; ++i) { scanf("%d%d", &u, &v); e[u].push_back(P(v, false)); e[v].push_back(P(u, false)); } if (fib.back() != n) no(); Check(1, fib.size() - 1); printf("YES"); }