2025年3月CSP,回顾 + 题解。
 
回顾 得分 100 - 100 - 80 - 100 - 15。
T1 T2大概花了 15min,T4 大概 30min 过掉,剩下时间都在写 T3, T5。
本场败笔在 T3,在 DAG 上 DFS 暴搜,没写记忆化,只拿了 80 分。卡在 395,与 400 失之交臂了(哭
T5 Link Cut Tree,神秘的高级数据结构,暂时不补。
题解 数值积分 按题意模拟。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <bits/stdc++.h>  #define  int long long using  namespace  std;void  solve ()     int  b, c, l, r;     cin >> b >> c >> l >> r;     if (l & 1 ) l++;     if (r & 1 ) r--;          int  res = 0 ;     for (int  i = l; i <= r; i += 2 ){         res += 2  * (i * i + b * i + c);      }      cout << res << '\n' ; } signed  main ()     ios::sync_with_stdio (0 );     cin.tie (0 );     solve ();     return  0 ; } 
机器人饲养指南 $$
记 $dp[i]$ 为投喂 $i$ 个时的最大快乐值,转移为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <bits/stdc++.h>  #define  int long long using  namespace  std;void  solve ()     int  n, m; cin >> n >> m;     vector<int > a (m + 1 )  ;     for (int  i = 1 ; i <= m; i++) cin >> a[i];          vector<int > dp (n + 1 )  ;     for (int  i = 1 ; i <= n; i++){         for (int  j = max (0ll , i - m); j < i; j++){             dp[i] = max (dp[i], dp[j] + a[i - j]);         }     }     cout << dp[n] << '\n' ; } signed  main ()     ios::sync_with_stdio (0 );     cin.tie (0 );     solve ();     return  0 ; } 
模板展开 理解题意:
那么抽象出来就是一张 DAG,每次修改点权或点权与出边,求值。
对每次 query,做一个记忆化,避免重复搜索。
同时学习一下 istringstream 字符串输入。
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 #include <bits/stdc++.h>  using  namespace  std;constexpr  int  mod = 1e9  + 7 ;unordered_map<string, int > StoI; vector<int > val (1005 )  ;vector<vector<int >> adj (1005 ); unordered_map<int , int > mp; int  idx = 1 ;inline  int  get_idx (string s)     if (StoI[s]) return  StoI[s];     return  StoI[s] = idx++; } inline  int  getlen (int  x)     if (mp[x]) return  mp[x];     int  res = val[x];     for (auto  &i : adj[x]){         res += getlen (i);         res %= mod;     }     return  mp[x] = res % mod; } void  solve ()     int  q; cin >> q;     cin.ignore ();     while (q--){         string line;         getline (cin, line);         istringstream iss (line)  ;         string op; iss >> op;         string tmpvar; iss >> tmpvar;         vector<string> expr; string ex;         while (iss >> ex) expr.emplace_back (ex);                  int  var = get_idx (tmpvar);         if (op == "1" ){             int  sum = 0 ;             for (auto  &s : expr){                 if (s[0 ] != '$' ){                     sum += s.size ();                     sum %= mod;                 }                 else {                     int  ss = get_idx (s.substr (1 , s.size () - 1 ));                     sum += getlen (ss);                     sum %= mod;                 }             }             val[var] = sum;             adj[var].clear ();         }         else  if (op == "2" ){             adj[var].clear ();             int  sum = 0 ;             for (auto  &s : expr){                 if (s[0 ] != '$' ){                     sum += s.size ();                     sum %= mod;                 }                 else {                     int  ss = get_idx (s.substr (1 , s.size () - 1 ));                     adj[var].emplace_back (ss);                 }             }             val[var] = sum;         }         else {             cout << getlen (var) << '\n' ;         }         mp.clear ();     } } signed  main ()     ios::sync_with_stdio (0 );     cin.tie (0 );     solve ();     return  0 ; } 
集体锻炼 观察到,固定右端点 $r$ 时,区间 $[l, r]$ 的 gcd 可能取值数不超过 $log(r-l+1)$。
因此维护每一段 gcd 不同的区间,每加入一个右端点,更新一遍区间,合并相同区间,逐个区间地去计算贡献。
时间复杂度 $O(n\log n)$。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 #include <bits/stdc++.h>  #define  int long long using  namespace  std;constexpr  int  mod = 998244353 ;int  gcd (int  a, int  b)     return  b ? gcd (b, a % b) : a; } struct  split {    int  r, g;     split (int  r, int  g) : r (r), g (g) {} }; void  solve ()     int  n; cin >> n;     vector<int >a (n + 1 );     for (int  i = 1 ; i <= n; i++) cin >> a[i];          vector<split>S;          int  res = 0 ;          for (int  i = 1 ; i <= n; i++){         vector<split>tmp;         S.emplace_back (i, a[i]);         for (int  j = 0 ; j < S.size (); j++){             S[j].g = gcd (S[j].g, a[i]);             if (tmp.empty ()){                 tmp.push_back (S[j]);             }             else  if (S[j].g == tmp.back ().g){                 tmp.back ().r = S[j].r;             }             else {                 tmp.push_back (S[j]);             }         }                  S.swap (tmp);         int  sum = S[0 ].r * (S[0 ].r + 1 ) / 2  * S[0 ].g % mod;         for (int  i = 1 ; i < S.size (); i++){             sum += (S[i].r * (S[i].r + 1 ) / 2  - S[i - 1 ].r * (S[i - 1 ].r + 1 ) / 2 ) % mod                      * S[i].g % mod;             sum %= mod;         }         res += sum * i;         res %= mod;     }          cout << res << '\n' ; } signed  main ()     ios::sync_with_stdio (0 );     cin.tie (0 );     solve ();     return  0 ; } 
成绩