A. Catch the Coin 
不难发现,只有硬币的 \(y\)  坐标大于等于 \(-1\)  时,\(Monocarp\)  才有可能收集到该硬币
code: 
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 #include  <bits/stdc++.h>  #define  x first #define  y second using  namespace  std;typedef  pair<int , int > PII;const  int  N = 200010 ;int  T;int  x, y;signed  main ()     cin >> T;     while  (T--)     {	         cin >> x >> y;                  if  (y >= -1 ) cout << "YES"  << endl;         else  cout << "NO"  << endl;     }     return  0 ; } 
B. Substring and Subsequence 
转化题意,只需计算出 \(b\)  中 能够作为 \(a\)  的子序列的最长子串 \(k\) ,包含 $ $ 作为子字符串和 \(b\)  作为子序列的字符串的最小可能长度即为 \(a.size()+k.size()\) 
code: 
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 #include  <bits/stdc++.h>  #define  x first #define  y second using  namespace  std;typedef  pair<int , int > PII;const  int  N = 200010 ;int  T;string a, b; signed  main ()     cin >> T;     while  (T--)     {         cin >> a >> b;                  int  res = 0 ;         for  (int  i = 0 ; i < b.size (); i++)             for  (int  j = 0 , k = i; j < a.size () && k < b.size (); j++)             {                 if  (a[j] == b[k]) k++;                 if  (j == a.size () - 1  || k == b.size ()) res = max (res, k - i);             }                      cout << a.size () + b.size () - res << endl;     }     return  0 ; } 
C. Two Movies 
对于 \(a[i]\)  和 \(b[i]\) ,它们的组合有以下几种情况:
\(a[i]=1,b[i]\neq1\) ,该观众给第一步电影留下评价最佳\(a[i]\neq1,b[i]=1\) ,该观众给第二部电影留下评价最佳\(a[i]=1,b[i]=1\) ,该观众留下的评价一定是正面评价,先不做选择,记为 \(cnt++\) \(a[i]=-1,b[i]=-1\) ,该观众留下的评价一定是负面评价,先不做选择,记为 \(cnt--\)  
\(cnt\)  即为可以让两个电影的评价增加的值
每个观众都操作过后,为了使两部电影的最低评分最大,需要使用 \(cnt\)  对两部电影的评分进行操作,使得两个评分最接近,这时两部电影的最低评分最大
code: 
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 #include  <bits/stdc++.h>  #define  x first #define  y second using  namespace  std;typedef  pair<int , int > PII;const  int  N = 200010 ;int  T;int  n;int  a[N], b[N];signed  main ()     cin >> T;     while  (T--)     {         cin >> n;         for  (int  i = 0 ; i < n; i++) cin >> a[i];         for  (int  i = 0 ; i < n; i++) cin >> b[i];                  int  r1 = 0 , r2 = 0 , c1 = 0 , c2 = 0 ;         for  (int  i = 0 ; i < n; i++)         {             if  (a[i] == 1  && b[i] == -1 ) r1++;             if  (a[i] == -1  && b[i] == 1 ) r2++;             if  (a[i] == 1  && b[i] == 1 ) c1++;             if  (a[i] == -1  && b[i] == -1 ) c2++;         }                  for  (int  i = 0 ; i < c1; i++)         {             if  (r1 <= r2) r1++;             else  r2++;         }         for  (int  i = 0 ; i < c2; i++)         {             if  (r1 >= r2) r1--;             else  r2--;         }                  cout << min (r1, r2) << endl;     }     return  0 ; } 
D. Smithing Skill 
最优策略显然是制造完一件武器后立刻熔化,每操作一次贡献 \(+2\) 
设\(best[i]\)  表示为用最多 \(i\)  块金属锭 制作并熔化一个武器所消耗金属锭的最小值,可以用双指针维护
设\(f[i]\)  为 用 \(i\)  块金属锭能够获得的最大经验值,考虑用 \(dp\) ,递推公式为: \(f[i]=f[i-best[i]]+2\) 
接下来遍历数组 \(c\) :
\(c[i]<=1e6\) ,对答案的贡献就是 \(f[c[i]]\) \(c[i]>1e6\) ,对于大于\(1e6\) 的部分,不难发现,每制作并熔化一个武器所消耗的金属锭最小值为 \(best[1e6]\) ,因此,可以先处理大于\(1e6\)  的部分对答案的贡献,为 \((\frac{c[i]-1e6-1}{best[1e6]}+1)\times 2\) ,再使用\(f\) 数组处理小于等于 \(1e6\)  的部分即可 
code: 
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 #include  <bits/stdc++.h>  #define  int long long #define  x first #define  y second using  namespace  std;typedef  pair<int , int > PII;const  int  N = 1000010 ;int  T;int  n, m;int  a[N], b[N], c[N];int  best[N], f[N];signed  main ()     ios::sync_with_stdio (false );     cin.tie (0 ), cout.tie (0 );     cin >> n >> m;     for  (int  i = 0 ; i < n; i++) cin >> a[i];     for  (int  i = 0 ; i < n; i++) cin >> b[i];     for  (int  i = 0 ; i < m; i++) cin >> c[i];     map<int , int > p;     for  (int  i = 0 ; i < n; i++)     {         if  (!p.count (a[i])) p[a[i]] = 1e9 ;         p[a[i]] = min (p[a[i]], a[i] - b[i]);     }     int  last = 0 ;     auto  it = p.begin ();     for  (int  i = 1 ; i < N; i++)     {         if  (it != p.end () && it -> x == i)          {             if  (it -> y < last || !last) last = it -> y;             it++;         }         best[i] = last;     }     for  (int  i = 1 ; i < N; i++)          if  (best[i]) f[i] = f[i - best[i]] + 2 ;     int  res = 0 ;     for  (int  i = 0 ; i < m; i++)     {         if  (c[i] >= N)         {             res += ((c[i] - N) / last + 1 ) * 2 ;             c[i] = N + (c[i] - N) % last - last;         }         res += f[c[i]];     }     cout << res << endl;     return  0 ; } 
E. Distance to Different 
通过观察发现
当序列中间有两个相同元素相邻时,例如 \(1,2,2,3\) ,将这两个相同的元素替换成两个不同的元素不影响答案,只有两个相同元素出现在头或尾,才不能被替换,因此,序列中间连续相同的元素块长度大于 \(2\)  时,对答案才有意义
对于序列中间每个块,里面的值是什么并不影响答案,因此,可以把题意转化为把数组分为 \(k\)  块,并且中间连续相同元素块长度大于 \(2\) ,可以用 \(dp\)  来完成操作
设 \(f[i][j]\)  为 前 \(i\)  个元素,分割成 \(j\)  个块的方案数,\(sum[i][j]\) ,为不超过 \(i\)  个元素,分割成 \(j\)  块的方案数
code: 
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 #include  <bits/stdc++.h>  #define  int long long using  namespace  std;const  int  N = 200010 , mod = 998244353 ;int  n, k;int  f[N][15 ], sum[15 ];signed  main ()     cin >> n >> k;     sum[0 ] = f[0 ][0 ] = 1 ;     for  (int  i = 1 ; i <= n; i++)     {         for  (int  j = 0 ; j <= k; j++)         {             f[i][min (j + 1 , k)] = (f[i][min (j + 1 , k)] + sum[j]) % mod;             if  (i > 2  && i < n) f[i][min (j + 1 , k)] = (f[i][min (j + 1 , k)] - f[i - 2 ][j] + mod) % mod;         }         for  (int  j = 0 ; j <= k; j++) sum[j] = (sum[j] + f[i][j]) % mod;     }     cout << f[n][k] << endl;     return  0 ; }