2024牛客寒假算法基础集训营1

1|0A-DFS搜索


暴力判就行

#include<bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using i128 = __int128; #define int long long using vi = vector<int>; using pii = pair<int, int>; using vii = vector<pii>; const int inf = INT_MAX, INF = LLONG_MAX; const int mod = 1e9 + 7; const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0}; using edge = array<int, 3>; void solve() { int n; string s; cin >> n >> s; int f = 0; for (int i = 0; i < n; i++) { if (s[i] != 'D') continue; for (int j = i + 1; j < n; j++) { if (s[j] != 'F') continue; for (int k = j + 1; k < n; k++) { if (s[k] != 'S') continue; f = 1; break; } break; } break; } cout << f << " "; f = 0; for (int i = 0; i < n; i++) { if (s[i] != 'd') continue; for (int j = i + 1; j < n; j++) { if (s[j] != 'f') continue; for (int k = j + 1; k < n; k++) { if (s[k] != 's') continue; f = 1; break; } break; } break; } cout << f << "\n"; } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int T; for (cin >> T; T; T--) solve(); return 0; }

2|0B-关鸡


只要分别堵住左右的边界就行。但是有一种特殊的情况就是左右的边界共用一个(0,2)点的情况。

#include<bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using i128 = __int128; #define int long long using vi = vector<int>; using pii = pair<int, int>; using vii = vector<pii>; const int inf = INT_MAX, INF = LLONG_MAX; const int mod = 1e9 + 7; const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0}; using edge = array<int, 3>; void solve() { int n; vector<set<int>> l(2), r(2); cin >> n; int a = 2, b = 2; for (int x, y; n; n--) { cin >> x >> y, --x; if (y <= 0) l[x].insert(y), a = 1; if (y >= 0) r[x].insert(y), b = 1; } for (int x = 0; x < 2 and a == 1; x++) { for (const auto &y: l[x]) { if (l[x ^ 1].count(y)) { a = 0; break; } else if (l[x ^ 1].count(y - 1)) { a = 0; break; } else if (l[x ^ 1].count(y + 1)) { a = 0; break; } } } for (int x = 0; x < 2 and b == 1; x++) { for (const auto &y: r[x]) { if (r[x ^ 1].count(y)) { b = 0; break; } else if (r[x ^ 1].count(y - 1)) { b = 0; break; } else if (r[x ^ 1].count(y + 1)) { b = 0; break; } } } int ans = 3; if (l[0].count(-1)) ans--; if (l[1].count(0)) ans--; if (r[0].count(1)) ans--; cout << min(a + b, ans) << "\n"; } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int T; for (cin >> T; T; T--) solve(); return 0; }

3|0C-按闹分配


首先可以想到最优的分配方法就是用时少的人先办理。

可以推出的是,插队插在x个人前面则ScSmin=xtcM,所以算x在求个和即可。

#include<bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using i128 = __int128; #define int long long using vi = vector<int>; using pii = pair<int, int>; using vii = vector<pii>; const int inf = INT_MAX, INF = LLONG_MAX; const int mod = 1e9 + 7; const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0}; using edge = array<int, 3>; i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int n, q, tc; cin >> n >> q >> tc; vi t(n); for (auto &i: t) cin >> i; t.push_back(0); sort(t.begin(), t.end()); for (int i = 1; i <= n; i++) t[i] += t[i - 1]; for (int m, x; q; q--) { cin >> m; x = m / tc; x = max(0ll, n - x); cout << t[x] + tc<< "\n"; } return 0; }

4|0D-数组成鸡


因为询问的范围并不算很大,并且最终的结果要乘积。所以其实整个数组可以改变的部分并不多。可以把每一个数变成0,然后再这个数的周围暴力枚举即可,只要超出边界就可以结束。

#include<bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using i128 = __int128; using ldb = long double; #define int i64 using vi = vector<int>; using pii = pair<int, int>; using vii = vector<pii>; const int inf = INT_MAX, INF = LLONG_MAX; const int mod = 1e9 + 7; const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0}; using edge = array<int, 3>; int power(int x, int y) { int ans = 1; while (y) { if (y & 1) ans = ans * x % mod; x = x * x % mod, y /= 2; } return ans; } int inv(int x) { return power(x, mod - 2); } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int n, q; cin >> n >> q; vi a(n); for (auto &i: a) cin >> i; sort(a.begin(), a.end()); set<int> cnt; auto check = [a, &cnt](int x) { i128 ans = 1; for (const auto &i: a) { ans = ans * (x + i); if (ans > 1e9 or ans < -1e9)break; } if (ans > 1e9 or ans < -1e9) return false; cnt.insert(ans); return true; }; for (int i = 0; i < n; i++) { if (i and a[i] == a[i - 1]) continue; for (int j = -a[i] - 1; check(j); j--); for (int j = -a[i] + 1; check(j); j++); } cnt.insert(0); for (int x; q; q--) { cin >> x; if (cnt.count(x)) cout << "Yes\n"; else cout << "No\n"; } return 0; }

5|0E-本题又主要考察了贪心


因为m只有10所以310级别的暴力枚举是可以接受的

#include<bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using i128 = __int128; #define int long long using vi = vector<int>; using pii = pair<int, int>; using vii = vector<pii>; const int inf = INT_MAX, INF = LLONG_MAX; const int mod = 1e9 + 7; const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0}; using edge = array<int, 3>; int n, m, res; vector<int> a, x, y; void dfs(int i) { if (i == m) { int ans = 1; for (int i = 1; i < n; i++) ans += (a[i] > a[0]); res = min(res, ans); return; } a[x[i]] += 3; dfs(i + 1); a[x[i]] -= 3; a[y[i]] += 3; dfs(i + 1); a[y[i]] -= 3; a[x[i]]++, a[y[i]]++; dfs(i + 1); a[x[i]]--, a[y[i]]--; return; } void solve() { cin >> n >> m, res = inf; a.resize(n), x.clear(), y.clear(); for (auto &i: a) cin >> i; for (int u, v; m; m--) { cin >> u >> v, u--, v--; if (u == 0 or v == 0) a[0] += 3; else x.push_back(u), y.push_back(v); } m = x.size(); dfs(0); cout << res << "\n"; } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int T; for (cin >> T; T; T--) solve(); return 0; }

6|0F-鸡数题!


根据题目,其实可以转化为第二类斯特林数。

#include<bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using i128 = __int128; #define int long long using vi = vector<int>; using pii = pair<int, int>; using vii = vector<pii>; const int inf = INT_MAX, INF = LLONG_MAX; const int mod = 1e9 + 7; const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0}; using edge = array<int, 3>; int power(int x, int y) { int ans = 1; while (y) { if (y & 1) ans = ans * x % mod; x = x * x % mod, y /= 2; } return ans; } int inv(int x) { return power(x, mod - 2); } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int n, m; cin >> n >> m; if (n < m) { cout << "0\n"; return 0; } vi fact(n + 1); fact[0] = 1; for (int i = 1; i <= n; i++) fact[i] = fact[i - 1] * i % mod; int res = 0; for (int i = 0, t; i <= m; i++) { t = power(i, n) * inv(fact[i]) % mod * inv(fact[m - i]) % mod; if ((m - i) % 2 == 0) res = (res + t) % mod; else res = (res - t + mod) % mod; } cout << res << "\n"; return 0; }

7|0why买外卖


把所有的优惠卷按照ai排序,然后枚举在前i个卷全部使用的情况下,是否可以满足原价大于等ai

也就是

m+j=1ibjai

是否成立

#include<bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using i128 = __int128; #define int long long using vi = vector<int>; using pii = pair<int, int>; using vii = vector<pii>; const int inf = INT_MAX, INF = LLONG_MAX; const int mod = 1e9 + 7; const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0}; using edge = array<int, 3>; void solve() { int n, m; cin >> n >> m; vector<pii> a(n); for (auto &[x, y]: a) cin >> x >> y; sort(a.begin(), a.end()); int res = m , cnt = m; for (const auto &[x, y]: a) { cnt += y; if( cnt >= x) res = max( res , cnt); } cout << res << "\n"; } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int T; for (cin >> T; T; T--) solve(); return 0; }

8|0H-01背包,但是bit


如果要使得当前背包中的物品重量不超过x只需要选择所有满足x|wi=x的物品即可。

在这种情况下,也就是要枚举所有的xm,然后计算出结果即可。

但是显然在满足小于等于m的情况下,二进制下1的个数越多越好。所以我们可以枚举m二进制下所有为1的位,然后把这一位变位0,把低位全部变为1来做x。这样符合条件的x不超过30个。

#include<bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using i128 = __int128; using ldb = long double; #define int i64 using vi = vector<int>; using pii = pair<int, int>; using vii = vector<pii>; const int inf = INT_MAX, INF = LLONG_MAX; const int mod = 1e9 + 7; const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0}; using edge = array<int, 3>; int power(int x, int y) { int ans = 1; while (y) { if (y & 1) ans = ans * x % mod; x = x * x % mod, y /= 2; } return ans; } int inv(int x) { return power(x, mod - 2); } void solve() { int n, m; cin >> n >> m; vi v(n), w(n); int res = 0; for (int i = 0; i < n; i++) cin >> v[i] >> w[i]; auto calc = [v, w, n](int x) { int ans = 0; for (int i = 0; i < n; i++) if ((x | w[i]) == x) ans += v[i]; return ans; }; res = max(res, calc(m)); for (int i = 0; i < 31; i++) if (m & (1 << i)) res = max(res, calc(m ^ (1 << i) | ((1 << i) - 1))); cout << res << "\n"; } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int TC; for (cin >> TC; TC; TC--) solve(); return 0; }

9|0I-It's bertrand paradox. Again!


两种方案,bit的方法相当于先随机出x,y在随机出r,buaa的方法相当于每次都直接随机出(x,y,r),自然的bit的分布更加均匀,而buaa的方法则相对集中在中心部位。

所以写出这两种方法,分别随机100次,然后看圆心在中间的情况(50x,y50)的概率,bit的概率大约是0.25,buaa的概率大约是0.5

根据这个分辨一下就好。

test()是我的暴力代码

#include<bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using i128 = __int128; using ldb = long double; #define int i64 using vi = vector<int>; using pii = pair<int, int>; using vii = vector<pii>; const int inf = INT_MAX, INF = LLONG_MAX; const int mod = 1e9 + 7; const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0}; using edge = array<int, 3>; int power(int x, int y) { int ans = 1; while (y) { if (y & 1) ans = ans * x % mod; x = x * x % mod, y /= 2; } return ans; } int inv(int x) { return power(x, mod - 2); } void test() { mt19937 mt{random_device()()}; uniform_int_distribution rdx(-99, 99); uniform_int_distribution rdr(1, 100); int n = 1e5; auto buaa = [&]() { vector<array<int, 3>> a; for (int t = n, x, y, r; t; t--) { while (true) { x = rdx(mt), y = rdx(mt), r = rdr(mt); if (r < 0 or abs(x + r) > 100 or abs(x - r) > 100 or abs(y + r) > 100 or abs(y - r) > 100) continue; break; } a.push_back({x, y, r}); } return a; }; auto bit = [&]() { vector<array<int, 3>> a; for (int t = n, x, y, r; t; t--) { x = rdx(mt), y = rdx(mt); while (true) { r = rdr(mt); if (r < 0 or abs(x + r) > 100 or abs(x - r) > 100 or abs(y + r) > 100 or abs(y - r) > 100) continue; break; } a.push_back({x, y, r}); } return a; }; int t = 100; ldb x = 0, y = 0; for (int i = 1; i <= t; i++) { ldb xx = 0, yy = 0; for (auto [x, y, r]: bit()) if (abs(x) <= 50 and abs(y) <= 50) xx += 1; for (auto [x, y, r]: buaa()) if (abs(x) <= 50 and abs(y) <= 50) yy += 1; x += xx / n, y += yy / n; cerr << "bit = " << xx / n << " buaa = " << yy / n << " \n"; } x /= t, y /= t; cout << fixed << setprecision(6); cout << "bit = " << x << " buaa = " << y << " \n"; } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); // test(); int n; cin >> n; ldb cnt = 0; for( int i = 1 , x , y , r ; i <= n ; i ++ ){ cin >> x >> y >> r; if( abs(x) <= 50 and abs(y) <= 50 ) cnt += 1; } cnt /= n; if( abs( cnt - 0.25) < abs(cnt-0.5)) cout << "bit-noob\n"; else cout << "buaa-noob\n"; return 0; }

10|0J-又鸟之亦心


i时刻,一定有一个人位于ai ,用set维护另一个人可能位于的位置,保证整个过程种set必须保证非空。这样我们就可以二分答案。

#include<bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using i128 = __int128; using ldb = long double; #define int i64 using vi = vector<int>; using pii = pair<int, int>; using vii = vector<pii>; const int inf = INT_MAX, INF = LLONG_MAX; const int mod = 1e9 + 7; const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0}; using edge = array<int, 3>; int power(int x, int y) { int ans = 1; while (y) { if (y & 1) ans = ans * x % mod; x = x * x % mod, y /= 2; } return ans; } int inv(int x) { return power(x, mod - 2); } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int n, x, y; cin >> n >> x >> y; vi a(n); for (auto &i: a) cin >> i; int l = 0, r = 1e9, res = -1; auto check = [=](int d) -> bool { int lst = y; set<int> s; if (abs(x - y) <= d) s.insert(x); else return false; for (int i: a) { if ( abs(i - lst) <= d) s.insert(lst); while (not s.empty() and *s.begin() < i - d) s.erase(*s.begin()); while (not s.empty() and *s.rbegin() > i + d) s.erase(*s.rbegin()); lst = i; if (s.empty()) break; } return not s.empty(); }; for (int mid; l <= r;) { mid = (l + r) / 2; if (check(mid)) res = mid, r = mid - 1; else l = mid + 1; } cout << res << "\n"; return 0; }

11|0K-牛镇公务员考试


i可以影响ai,所以图一定是一个内向基环树森林。

基环树上的链无法影响答案,因为可以从环上的结点反推出答案。对于任意一个环,随便选择一个点,然后枚举所有的答案,最后判断一下即可。

#include<bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using i128 = __int128; using ldb = long double; #define int i64 using vi = vector<int>; using pii = pair<int, int>; using vii = vector<pii>; const int inf = INT_MAX, INF = LLONG_MAX; const int mod = 998244353; const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0}; using edge = array<int, 3>; int power(int x, int y) { int ans = 1; while (y) { if (y & 1) ans = ans * x % mod; x = x * x % mod, y /= 2; } return ans; } int inv(int x) { return power(x, mod - 2); } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int n; cin >> n; vi a(n); vector<string> s(n); vi vis(n), inDeg(n); for (int i = 0; i < n; i++) cin >> a[i] >> s[i], a[i]--, inDeg[a[i]]++; queue<int> q; for (int i = 0; i < n; i++) if (inDeg[i] == 0) q.push(i); for (int x, y; not q.empty();) { x = q.front(), q.pop(); vis[x] = 1, y = a[x]; if (--inDeg[y] == 0) q.push(y); } int res = 1; for (int i = 0, ans; i < n; i++) { if (vis[i]) continue; ans= 0, vis[i] = 1; for (int u = 0, v, t; u < 5; u++) { t = i, v = u; do { v = s[t][v] - 'A'; t = a[t]; vis[t] = 1; } while (t != i); ans += v == u; } res = res * ans % mod; } cout << res << "\n"; return 0; }

12|0L-要有光


根据高中的地理知识就可以猜出,当太阳的高度为0时,影子面积最大

#include<bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using i128 = __int128; using ldb = long double; #define int long long using vi = vector<int>; using pii = pair<int, int>; using vii = vector<pii>; const int inf = INT_MAX, INF = LLONG_MAX; const int mod = 1e9 + 7; const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0}; using edge = array<int, 3>; int power(int x, int y) { int ans = 1; while (y) { if (y & 1) ans = ans * x % mod; x = x * x % mod, y /= 2; } return ans; } int inv(int x) { return power(x, mod - 2); } void solve() { ldb d, c, h, w, x, y, res; cin >> c >> d >> h >> w; x = 2 * c, y = 2 * w; res = x * y - c * w; cout << fixed << setprecision(8) << res << "\n"; return; } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int T; for (cin >> T; T; T--) solve(); return 0; }

13|0M-牛客老粉才知道的秘密


#include<bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using i128 = __int128; #define int long long using vi = vector<int>; using pii = pair<int, int>; using vii = vector<pii>; const int inf = INT_MAX, INF = LLONG_MAX; const int mod = 1e9 + 7; const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0}; using edge = array<int, 3>; void solve() { int n, res = 0; cin >> n; res = n / 6; if (n % 6 != 0) res = res * 2; cout << res << "\n"; } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int T; for (cin >> T; T; T--) solve(); return 0; }

__EOF__

本文作者PHarr
本文链接https://www.cnblogs.com/PHarr/p/18006794.html
关于博主:前OIer,SMUer
版权声明CC BY-NC 4.0
声援博主:如果这篇文章对您有帮助,不妨给我点个赞
posted @   PHarr  阅读(45)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示