找回密码
 立即注册
首页 业界区 科技 2025牛客寒假算法基础集训营2 题解

2025牛客寒假算法基础集训营2 题解

觞刈 2025-6-9 18:24:04
Preface

作为一名半退役选手,个人感觉本场难度不是太大,感觉和去年比难度貌似是下降了。在打的时候实在是由于乱七八糟的原因(包括不限于眼瞎,眼瞎,还有眼瞎),打得一般般。
感觉本场模拟题偏多,实在是吃屎。
我会在代码一些有必要的地方加上注释,签到题可能一般就不会写了.
以下是代码火车头:
  1. #include <iostream>
  2. #include
  3. #include <cstring>
  4. #include <cmath>
  5. #include <vector>
  6. #include <set>
  7. #include <queue>
  8. #include <map>
  9. #include <unordered_map>
  10. #include <iomanip>
  11. #define endl '\n'
  12. #define int long long
  13. #define rep(i,a,b) for(int i=(a);i<=(b);i++)
  14. #define rep2(i,a,b) for(int i=(a);i>=(b);i--)
  15. using namespace std;
  16. template<typename T>
  17. void cc(const vector<T> &tem) {
  18.     for (const auto &x: tem) cout << x << ' ';
  19.     cout << endl;
  20. }
  21. template<typename T>
  22. void cc(const T &a) { cout << a << endl; }
  23. template<typename T1, typename T2>
  24. void cc(const T1 &a, const T2 &b) { cout << a << ' ' << b << endl; }
  25. template<typename T1, typename T2, typename T3>
  26. void cc(const T1 &a, const T2 &b, const T3 &c) { cout << a << ' ' << b << ' ' << c << endl; }
  27. void cc(const string &s) { cout << s << endl; }
  28. void fileRead() {
  29. #ifdef LOCALL
  30.     freopen("D:\\AADVISE\\Clioncode\\untitled2\\in.txt", "r", stdin);
  31.     freopen("D:\\AADVISE\\Clioncode\\untitled2\\out.txt", "w", stdout);
  32. #endif
  33. }
  34. void kuaidu() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); }
  35. inline int max(int a, int b) {
  36.     if (a < b) return b;
  37.     return a;
  38. }
  39. inline double max(double a, double b) {
  40.     if (a < b) return b;
  41.     return a;
  42. }
  43. inline int min(int a, int b) {
  44.     if (a < b) return a;
  45.     return b;
  46. }
  47. inline double min(double a, double b) {
  48.     if (a < b) return a;
  49.     return b;
  50. }
  51. void cmax(int &a, const int &b) { if (b > a) a = b; }
  52. void cmin(int &a, const int &b) { if (b < a) a = b; }
  53. void cmin(double &a, const double &b) { if (b < a) a = b; }
  54. void cmax(double &a, const double &b) { if (b > a) a = b; }
  55. using PII = pair<int, int>;
  56. using i128 = __int128;
  57. using vec_int = std::vector<int>;
  58. using vec_char = std::vector<char>;
  59. using vec_double = std::vector<double>;
  60. using vec_int2 = std::vector<std::vector<int> >;
  61. using que_int = std::queue<int>;
复制代码
Problem E. 一起走很长的路!

一个很典典的题,简简单单推式子就好了,比\(C\)题简单不少。

设前缀和\(pre_i=a_1+a_2+...+a_i\),那么需要满足条件:\(pre_i-pre_{l-1}>=a_{i+1}\),\(l r1) return;        if (l1  1;        if (r1  r1) return info();        if (l1  1;        if (r1 > T;    while (T--) {        cin >> n;        int q;        cin >> q;        rep(i, 1, n) {            cin >> A;            pre += A;            pre += pre[i - 1];        }        seg.clear(1, n - 1);         rep(i, 1, n-1) {            dis = pre - A[i + 1];            seg.add(i, i, dis);        }         rep(i, 1, q) {            int l, r;            cin >> l >> r;            int tem = seg.qry(l, r - 1).mmin;            int ans = 0;            if (tem < pre[l - 1]) {                ans = pre[l - 1] - tem;            }            cc(ans);        }     }    return 0;}[/code]Problem F. 一起找神秘的数!

稍微画一画就能发现,满足条件需要\(x=y\)。
具体推的话,可以用韦恩图画一下就好了,记住,‘或’是求并集,异或是去重,and 是求交集。
  1. //--------------------------------------------------------------------------------
  2. const int N = 1e5 + 10;
  3. const int M = 1e6 + 10;
  4. const int mod = 1e9 + 7;
  5. const int INF = 1e16;
  6. int n, m, T;
  7. //--------------------------------------------------------------------------------
  8. //struct or namespace:
  9. //--------------------------------------------------------------------------------
  10. signed main() {
  11.         fileRead();
  12.         kuaidu();
  13.         T = 1;
  14.         //cin >> T;
  15.         while (T--) {
  16.                 bool fl = 0;
  17.                 rep(i, 1, 7) {
  18.                         int a;
  19.                         cin >> a;
  20.                         if (a == 4 or a == 7) fl = 1;
  21.                 }
  22.                 if (!fl) cc("YES");
  23.                 else cc("NO");
  24.         }
  25.         return 0;
  26. }
复制代码
Problem G. 一起铸最好的剑!

直接模拟就好了,不要直接用\(pow\)函数就好。
  1. //--------------------------------------------------------------------------------
  2. const int N = 5e5 + 10;
  3. const int M = 1e6 + 10;
  4. const int mod = 1e9 + 7;
  5. const int INF = 1e16;
  6. int n, m, T;
  7. int A[N];
  8. //--------------------------------------------------------------------------------
  9. //struct or namespace:
  10. //--------------------------------------------------------------------------------
  11. signed main() {
  12.         fileRead();
  13.         kuaidu();
  14.         T = 1;
  15.         //cin >> T;
  16.         while (T--) {
  17.                 cin >> n;
  18.                 rep(i, 1, n) cin >> A[i];
  19.                 sort(A + 1, A + n + 1);
  20.                 // rep(i, 1, n) cc(A[i]);
  21.                 int val = A[(n + 1 + 1) / 2] - 1;
  22.                 cc(val);
  23.         }
  24.         return 0;
  25. }
复制代码
Problem H. 一起画很大的圆!

最吃屎的时候,交了\(12\)发才过,还是最后蒙过去的。
首先先读题,边界!一开始读题读成了内部也可以,然后就先固定了两个点在斜线,然后找了最接近斜线的横坐标的每一个点去判断,时间复杂度按理来说是横坐标或者纵坐标的差值,\(1\)秒应该是能勉强跑过才对的,但是\(wa\)了,要不就是\(t\)了。
然后发现是在边界上...,但是依旧不会,脑子已经秀逗了。
最后暴力枚举了角落边界和中间边界的位置,然后跑过的。(其实也是有直觉是感觉两个点在角落,一个点在另一个同侧的角落,但是不确定)
  1. //--------------------------------------------------------------------------------
  2. const int N = 2e5 + 10;
  3. const int M = 1e6 + 10;
  4. const int mod = 1e9 + 7;
  5. const int INF = 1e16;
  6. int n, m, T;
  7. char s[N];
  8. //--------------------------------------------------------------------------------
  9. //struct or namespace:
  10. //--------------------------------------------------------------------------------
  11. signed main() {
  12.         fileRead();
  13.         kuaidu();
  14.         T = 1;
  15.         cin >> T;
  16.         while (T--) {
  17.                 cin >> n >> m;
  18.                 if (n == m) {
  19.                         cc("NO");
  20.                         continue;
  21.                 }
  22.                 if (m >= n - m + 1) {
  23.                         if (n - m - 1 <= 25 and n >= 4 and m >= 3) {
  24.                                 cc("YES");
  25.                                 s[1] = 'a';
  26.                                 s[n] = 'a';
  27.                                 rep(i, n-m+1, m) s[i] = 'a';
  28.                                 rep(i, 2, n-m+1-1) {
  29.                                         s[i] = 'a' + i - 1;
  30.                                         s[n - i + 1] = s[i];
  31.                                 }
  32.                                 rep(i, 1, n) { cout << s[i]; }
  33.                                 cout << endl;
  34.                         }
  35.                         else {
  36.                                 cc("NO");
  37.                         }
  38.                 }
  39.                 else {
  40.                         if (m - 1 + (n - m - m) <= 25) {
  41.                                 cc("YES");
  42.                                 int k = m - 1 + (n - m - m);
  43.                                 int x = n - k - 2, y = k - x;
  44.                                 rep(i, 1, x) { cout << char('a' + i); }
  45.                                 cout << 'a';
  46.                                 rep(i, x+1, x+y) { cout << char('a' + i); }
  47.                                 cout << 'a';
  48.                                 rep(i, 1, x) { cout << char('a' + i); }
  49.                                 cout << endl;
  50.                         }
  51.                         else {
  52.                                 cc("NO");
  53.                         }
  54.                 }
  55.         }
  56.         return 0;
  57. }
复制代码
Problem I. 一起看很美的日落!

一个典典的树形dp,但是赛时没有时间做了,应该是有铜+的难度的。
首先我们对于每一位可以独立看待,于是每个点的权值变成了0或者1,然后经典树形dp。
设\(dp_x\)是包含了\(x\)的联通块的\(ans\),\(f_{x,0}\)是联通块里0的个数,\(f_{x,1}\)同理,\(g_x\)是联通块大小。
然后考虑如何合并两个联通块:
  1. //--------------------------------------------------------------------------------
  2. const int N = 2e5 + 10;
  3. const int M = 1e6 + 10;
  4. const int mod = 1e9 + 7;
  5. const int INF = 1e16;
  6. int n, m, T;
  7. int pre[N][31];
  8. int suf[N][31];
  9. string s;
  10. //--------------------------------------------------------------------------------
  11. //struct or namespace:
  12. //--------------------------------------------------------------------------------
  13. bool check(int len) {
  14.         rep(i, 1, n) {
  15.                 int l = i, r = i + len - 1;
  16.                 if (l < 1 or r > n) break;
  17.                 if (pre[l - 1][s[l] - 'a'] or suf[r + 1][s[r] - 'a']) {
  18.                         return 1;
  19.                 }
  20.         }
  21.         return 0;
  22. }
  23. signed main() {
  24.         fileRead();
  25.         kuaidu();
  26.         T = 1;
  27.         //cin >> T;
  28.         while (T--) {
  29.                 cin >> n;
  30.                 cin >> s;
  31.                 s = ' ' + s;
  32.                 rep(i, 1, n) {
  33.                         rep(j, 0, 25) pre[i][j] = pre[i - 1][j];
  34.                         pre[i][s[i] - 'a'] = 1;
  35.                 }
  36.                 rep2(i, n, 1) {
  37.                         rep(j, 0, 25) suf[i][j] = suf[i + 1][j];
  38.                         suf[i][s[i] - 'a'] = 1;
  39.                 }
  40.                 int ans = 0;
  41.                 int l = 0, r = n;
  42.                 while (l + 1 != r) {
  43.                         int mid = l + r >> 1;
  44.                         if (check(mid)) l = mid;
  45.                         else r = mid;
  46.                 }
  47.                 cc(l);
  48.         }
  49.         return 0;
  50. }
复制代码
我觉得式子很显然,大家看了就晓得了。代码很简洁,顺手抄了个题解的取模类。
  1. //--------------------------------------------------------------------------------
  2. const int N = 2e5 + 10;
  3. const int M = 1e6 + 10;
  4. const int mod = 1e9 + 7;
  5. const int INF = 1e16;
  6. int n, m, T;
  7. //--------------------------------------------------------------------------------
  8. //struct or namespace:
  9. class SEG {
  10. #define xl x+x
  11. #define xr x+x+1
  12.     //TODO 节点维护信息、apply函数、up函数
  13.     struct info {
  14.         int mmin = INF;
  15.         void apply(int k) {
  16.             mmin = k;
  17.         }
  18.         friend info operator+(const info &q1, const info &q2) {
  19.             info q;
  20.             q.mmin = min(q1.mmin, q2.mmin);
  21.             return q;
  22.         }
  23.     };
  24.     int L, R;
  25.     info F[unsigned(N * 2.7)];
  26.     void init(int x, int l, int r) {
  27.         if (l == r) {
  28.             F[x] = info();
  29.             return;
  30.         }
  31.         int mid = l + r >> 1;
  32.         init(xl, l, mid), init(xr, mid + 1, r);
  33.         F[x] = F[xl] + F[xr];
  34.     }
  35.     void add(int x, int l, int r, int l1, int r1, int k) {
  36.         if (l1 > r1) return;
  37.         if (l1 <= l and r <= r1) {
  38.             F[x].apply(k);
  39.             return;
  40.         }
  41.         int mid = l + r >> 1;
  42.         if (r1 <= mid) add(xl, l, mid, l1, r1, k);
  43.         else if (mid < l1) add(xr, mid + 1, r, l1, r1, k);
  44.         else add(xl, l, mid, l1, mid, k), add(xr, mid + 1, r, mid + 1, r1, k);
  45.         F[x] = F[xl] + F[xr];
  46.     }
  47.     info qry(int x, int l, int r, int l1, int r1) {
  48.         if (l1 > r1) return info();
  49.         if (l1 <= l and r <= r1) return F[x];
  50.         int mid = l + r >> 1;
  51.         if (r1 <= mid) return qry(xl, l, mid, l1, r1);
  52.         else if (mid < l1) return qry(xr, mid + 1, r, l1, r1);
  53.         else { return qry(xl, l, mid, l1, mid) + qry(xr, mid + 1, r, mid + 1, r1); }
  54.     }
  55. #undef xl
  56. #undef xr
  57. public:
  58.     void clear(int l, int r) {
  59.         L = l, R = r;
  60.         init(1, l, r);
  61.     }
  62.     void add(int l, int r, int k) { add(1, L, R, l, r, k); }
  63.     info qry(int l, int r) { return qry(1, L, R, l, r); }
  64. };
  65. SEG seg;
  66. int A[N], pre[N], dis[N];
  67. //--------------------------------------------------------------------------------
  68. signed main() {
  69.     fileRead();
  70.     kuaidu();
  71.     T = 1;
  72.     //cin >> T;
  73.     while (T--) {
  74.         cin >> n;
  75.         int q;
  76.         cin >> q;
  77.         rep(i, 1, n) {
  78.             cin >> A[i];
  79.             pre[i] += A[i];
  80.             pre[i] += pre[i - 1];
  81.         }
  82.         seg.clear(1, n - 1);
  83.         rep(i, 1, n-1) {
  84.             dis[i] = pre[i] - A[i + 1];
  85.             seg.add(i, i, dis[i]);
  86.         }
  87.         rep(i, 1, q) {
  88.             int l, r;
  89.             cin >> l >> r;
  90.             int tem = seg.qry(l, r - 1).mmin;
  91.             int ans = 0;
  92.             if (tem < pre[l - 1]) {
  93.                 ans = pre[l - 1] - tem;
  94.             }
  95.             cc(ans);
  96.         }
  97.     }
  98.     return 0;
  99. }
复制代码
Problem L. 还会再见吗?

看了题解,虚树。
于是直接再见。
学虚树不如继续搞开发。
Problem M. 那是我们的影子

赛时没有做出来,赛后看题解发现不算太难。
但是个人感觉难度应该和\(I\)差不多才对。只能说这种题自己总会写的复杂,感慨大佬写的代码很简洁。
感觉官方题解写的很好很清楚,建议去看(不是自己懒了
借鉴了\(Heltion\)的代码:
  1. //--------------------------------------------------------------------------------
  2. const int N = 5e5 + 10;
  3. const int M = 1e6 + 10;
  4. const int mod = 1e9 + 7;
  5. const int INF = 1e16;
  6. int n, m, T;
  7. int A[N];
  8. //--------------------------------------------------------------------------------
  9. //struct or namespace:
  10. //--------------------------------------------------------------------------------
  11. signed main() {
  12.         fileRead();
  13.         kuaidu();
  14.         T = 1;
  15.         //cin >> T;
  16.         while (T--) {
  17.                 cin >> n;
  18.                 rep(i, 1, n) {
  19.                         int a, b;
  20.                         cin >> a >> b;
  21.                         cc(b - a + 1);
  22.                 }
  23.         }
  24.         return 0;
  25. }
复制代码
PostScript

只能说自己吃屎吃得太多,有些题自己写的太烂,点名批评\(h\)题。
感觉难度比去年真的少了很多,不知道是不是错觉。
题解如果有误希望可以指出来。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册