竞赛结果:Contestant,3202nd,Solved ABC,+22
todo
因为博主太困所以打算等下周空闲时间把这场和上场的题意补上。
A.Raise Both Hands 思路 打表(这能叫做一个表吗?)即可。
代码 1 2 3 4 5 6 7 8 9 10 11 void  solve ()     int  l, r;     cin >> l >> r;     if  (l && !r)         cout << "Yes"  << endl;     else  if  (!l && r)         cout << "No"  << endl;     else          cout << "Invalid"  << endl; } 
B.Binary Alchemy 思路 按规则模拟即可,为了缩减代码量我直接采用了 max 和 min 来替代一层 if 判断,增加的复杂度无伤大雅。
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 void  solve ()     int  n;     cin >> n;     vector<vector<int >> vec (n + 1 , vector <int >(n + 1 ));     for  (int  i = 1 ; i <= n; i++)         for  (int  j = 1 ; j <= i; j++)             cin >> vec[i][j];     int  element = 1 ;     for  (int  ele = 1 ; ele <= n; ele++)         element = vec[max (element, ele)][min (ele, element)];     cout << element << endl; } 
C.Word Ladder 思路 显然,因为修改本身没有限制,所以最少的修改次数必然是两个字符串不同字符的字符个数。
下面考虑如何让每次修改字典序最小。
显而易见,将一个字典序大的字符修改为一个字典序小的字符,字符串的整体字典序会下降,反之上升。而字典序的比较规则是从前往后比较,即为前面的字典序下降对整体字符串字典序的影响更大,而后面字符字典序上升对整体字符串字典序影响更小。
所以,为了让每次修改后的字典序是最优,我们首先正序修改会导致字典序下降的字符,让字典序“速降”,再倒序修改会导致字典序上升的字符,让字典序“缓升”。这样的解法就是最优的。
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 void  solve ()     string s, t;     cin >> s >> t;     vector<string> ans;     vector<int > inc,dec;     int  n = s.size ();     for  (int  i = 0 ; i < n; i++)     {         if  (s[i] < t[i])             inc.push_back (i);         else  if  (s[i] > t[i])             dec.push_back (i);     }     for  (auto  &v : dec)         s[v] = t[v], ans.push_back (s);     reverse (all (inc));     for  (auto  &v : inc)         s[v] = t[v], ans.push_back (s);     cout << ans.size () << endl;     for  (auto  &s : ans)         cout << s << endl; } 
以下为补题部分。 
D.Cross Explosion 思路 朴素的暴力 直接根据题意暴力即可,开启O3优化后,对于本题会TLE两个点,但是大部分样例都能过,证明只要在暴力上进行优化即可。
暴力的优化 暴力的优化一共有两个方向,一种是用数组维护当前节点的相邻节点,另外一种是 set 记录目前剩余节点并二分查找相邻节点。
我赛时写的第一种优化,没优化出来。
但这种优化好像有些边界条件模糊,还真不如二分set好懂,于是干脆只写二分set了。
代码 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 void  solve ()      int  h, w, q;     cin >> h >> w >> q;     vector<set<int >> col (w + 1 ), row (h + 1 );     for  (int  i = 1 ; i <= h; i++)         for  (int  j = 1 ; j <= w; j++)             row[i].insert (j), col[j].insert (i);     for  (int  i = 1 ; i <= h; i++)         row[i].insert (0 ), row[i].insert (w + 1 );     for  (int  i = 1 ; i <= w; i++)         col[i].insert (0 ), col[i].insert (h + 1 );     int  ans = h * w;     while  (q--)     {         int  x, y;         cin >> x >> y;         auto  it = row[x].lower_bound (y), it2 = prev (it);          if  (*it == y)          {             ans--, row[x].erase (y), col[y].erase (x);             continue ;         }         if  (*it <= w)              ans--, row[x].erase (*it), col[*it].erase (x);         if  (*it2)              ans--, row[x].erase (*it2), col[*it2].erase (x);         it = col[y].lower_bound (x), it2 = prev (it);          if  (*it <= h)             ans--, row[*it].erase (y), col[y].erase (*it);         if  (*it2)             ans--, row[*it2].erase (y), col[y].erase (*it2);     }     cout << ans << endl; } 
E.Avoid K Partition 思路 时间复杂度 $O(N^2)$ 二维 dp,定义 $dp[i]$ 为在选定点 $i$ 的时候,从 $1$ 选到 $i$ 的方案的总和。
初始值: $dp[1] = 1$ ,终值取  $dp[n+1]$ ,过程中的推导式为 $dp[n] = \sum_{1 \leq m \lt n} \left(0\text{ if }\sum_{k=m}^{n-1} A_i = K \text{ else } dp[m] \right) $。
注意:虽然这个式子中的$\sum A_i$部分可以用前缀和,但是时间复杂度最坏是$N^2$,这个推导式过不了本题目,要对其进行优化。
优化正解 可以发现转移只会从 $\sum^i_j {A_i \neq k}$ 的区间来,所以分别记录目前的总方案数和上述区间的方案数,则 $dp[i] = sum-invalid$。
开一个 map 进行缓存,令 $mp[pref]$ 等价前缀和为 $pref$ 时的合法方案数,则 $invalid = mp[sum-k]$。答案得以求出。
代码 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 constexpr  int  MOD = 998244353 ;using  i64 = long  long ;void  solve ()     int  n;     i64 k;     cin >> n >> k;     vector<int > vec (n + 1 )  ;     for  (int  i = 1 ; i <= n; i++)         cin >> vec[i];     vector<i64> dp (n + 1 )  ;     dp[1 ] = 1 ;     map<i64, int > mp;     mp[0 ] = 1 ;     i64 sum = 0 , all = 1 ;     for  (int  i = 1 ; i <= n; i++)     {         sum += vec[i];         int  invalid = mp[sum - k];         dp[i] = (all - invalid + MOD) % MOD;         all = (all + dp[i]) % MOD;         mp[sum] = (mp[sum] + dp[i]) % MOD;     }     cout << dp[n] << endl; }