A~F 个人题解

A

#include <iostream>
using namespace std;

int main() {
  int n;
  cin>>n;
  cout<<(n == 1 ? "NO" : "YES")<<'\n';
  
  return 0;
}

B

#include <iostream>
#include <algorithm>
using namespace std;

int a[200005];

int main() {
  int t;
  cin>>t;
  while (t--) {
    int n;
    cin>>n;
    long long s = 0;
    for (int i=1; i<=n; i++)
      cin>>a[i], s += a[i];
    sort(a+1, a+1+n);
    cout<<s*2-a[1]-a[2]<<'\n';
  }
  
  return 0;
}

C

必存在一个长度为2的区间 其结果最大
因为数字越多 max不会变 但mex要么不变 要么变小
所以只要枚举所有相邻两个数 求max和mex即可

#include <iostream>
using namespace std;

int a[300005];

int mex(int a, int b) {
  int ans = 0;
  if (a == 0 || b == 0) {
    ans++;
    if (a == 1 || b == 1)
      ans++;
  }
  return ans;
}

int main() {
  int t;
  cin>>t;
  while (t--) {
    int n, x, pre, mx = -1e9;
    cin>>n>>pre;
    for (int i=1; i<=n-1; i++)
      cin>>x, mx = max(mx, max(x, pre) - mex(x, pre)), pre = x;
    cout<<mx<<'\n';
  }
  
  return 0;
}

D

赛后才知道可以贪心
要么删第一个 要么删最后一个
否则 如果删的是中间的 把这个数换为第一个或最后一个 结果一定更小 所以删其他的数一定不会更优
所求可看成“离差和” 类比方差 数据越集中离差和越小

#include <iostream>
#include <algorithm>
using namespace std;

int a[200005];

int main() {
  int t;
  cin>>t;
  while (t--) {
    int n;
    cin>>n;
    for (int i=1; i<=n; i++)
      cin>>a[i];
    sort(a+1, a+1+n);
    long long ans1 = 0, ans2 = 0;
    for (int i=1; i<=n-1; i++)
      ans1 += abs(a[i]-a[n/2]);
    for (int i=2; i<=n; i++)
      ans2 += abs(a[i]-a[n/2+1]);
    cout<<min(ans1, ans2)<<'\n';
  }
  
  return 0;
}

E

dp
记录后缀数字和为0~9中的某个数的子数组个数
可以先预处理出任意两个个位数的和的数位和
可以用滚动数组优化

#include <iostream>
#include <cstring>
using namespace std;

int main() {
  int g[10][10] = {0};
  for (int i=0; i<10; i++)
    for (int j=0; j<10; j++)
      for (auto &ch: to_string(i+j))
        g[i][j] += ch-'0';
  int t;
  cin>>t;
  while (t--) {
    string s;
    cin>>s;
    int n = s.size(), dp[2][10] = {0};
    long long ans = 0;
    for (int i=1; i<=n; i++) {
      memset(dp[i&1], 0, sizeof dp[i&1]);
      dp[i&1][s[i-1]-'0']++;
      ans += s[i-1]-'0';
      for (int j=0; j<10; j++)
        dp[i&1][g[j][s[i-1]-'0']] += dp[(i-1)&1][j], ans += dp[(i-1)&1][j]*g[j][s[i-1]-'0'];
    }
    cout<<ans<<'\n';
  }
  
  return 0;
}

F

一定存在一种划分 划分的块数小于等于2 其结果最大

因为,如果划分的块数大于等于3,每3个连续的块可继续合并为1块。可以断言原先3个块的与运算结果一定小于或等于异或运算合并后的结果。因为:

  • 当与运算结果的二进制的某一位为1时,要求原先的3个块的该位都为1,此时异或运算和它是等价的
  • 当只有1个块的某位为1时,异或运算结果的该位仍然为1,而与运算结果的该位为0,此时异或运算结果大于与运算结果

故对于3个及以上的块,使用异或运算合并它们,一定不会更亏。

#include <iostream>
using namespace std;

int a[300005];

int main() {
  int t;
  cin>>t;
  while (t--) {
    int n, s = 0;
    cin>>n;
    for (int i=1; i<=n; i++)
      cin>>a[i], s ^= a[i];
    int mx = s, ans = 0;
    for (int i=1; i<=n; i++)
      ans ^= a[i], mx = max(mx, ans&(s^ans));
    cout<<mx<<'\n';
  }
  
  return 0;
}