比赛地址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"); }