A. Brogramming Contest 题目链接:https://codeforces.com/contest/2064/problem/A
如果 s 是以 0 开头那么我们每次只要找到 0, 1 交界的地方进行操作即可;
如果 s 是以 1 开头那么我们需要多进行一次操作把字符串变成以 0 开头的.
1 2 3 4 5 6 7 8 9 10 11 12 13 void solve () { int n; string s; cin >> n >> s; int ans = 0 ; for (int i = 0 ;i < n - 1 ;i++) { if (s[i] != s[i + 1 ]) ans++; } if (s[0 ] == '0' ) cout << ans << '\n' ; else cout << ans + 1 << '\n' ; }
B. Variety is Discouraged 题目链接:https://codeforces.com/contest/2064/problem/B
删除元素的同时数组长度也会变小;
假设现在某种元素的个数只有 1 个, 我们将其删掉后数组中元素种类和数组长度都减少 1 对于得分其实没有影响;
所以在不操作时的得分已经是最大得分了, 那么我们只需在得分不变的情况下尽可能减少数组长度;
基于上面第一个判断, 我们只要找到一个最大的连续片段, 这个片段中所有元素的个数都为 1;
注意特判一下所有元素个数都为 1 和不为 1 的情况即可.
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 void solve () { int n; cin >> n; vector<int > v (n + 1 ) ; map<int , int > mp; for (int i = 1 ;i <= n;i++) { cin >> v[i]; mp[v[i]] ++; } int mxl = 0 ; int l = 0 , r = 0 , now = 0 ; for (int i = 1 ;i <= n;i++) { if (mp[v[i]] == 1 ) { if (!now) now = i; } else { if (now) { int len = i - now; if (len > mxl) { mxl = len; l = now; r = i - 1 ; } now = 0 ; } } } if (now) { int len = n - now + 1 ; if (len > mxl) { mxl = len; l = now; r = n; } } if (mxl == 0 ) cout << 0 << '\n' ; else cout << l << " " << r << '\n' ; }
C. Remove the Ends 题目链接:https://codeforces.com/contest/2064/problem/C
现在假设我们任取一个位置 i, 根据题目可以判断:
-这个位置之前的所有负数我们都不能取, 而所有正数都能取到;
-这个位置之后的所有正数我们都不能取, 而所有负数都能取到;
所以我们对数组中的正数做前缀和处理, 负数做后缀和处理, 然后枚举每个位置取 max 即可.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 void solve () { int n; cin >> n; vector<int > v (n + 1 ) ; for (int i = 1 ;i <= n;i++) cin >> v[i]; vector<ll> pref (n + 3 ) , prez (n + 3 ) ; for (int i = 1 ;i <= n;i++) prez[i] = prez[i - 1 ] + max (0 , v[i]); for (int i = n;i >= 1 ;i--) pref[i] = pref[i + 1 ] + max (0 , -v[i]); ll ans = 0 ; for (int i = 1 ;i <= n;i++) ans = max (ans, pref[i] + prez[i]); cout << ans << '\n' ; }
D. Eating 题目链接:https://codeforces.com/contest/2064/problem/D
首先如果两个数最高位相同, 那么异或后最高位会被消掉否则最高位会被保留;
其次是异或运算满足结合律, 即 (a ^ b) ^ c = (a ^ c) ^ b ;
所以如果某个数的最高位比 x 低显然我们是可以将其吃掉的, 同时 x 的最高位依然会被保留;
于是我们只要从前找到一个最高位和 x 相等的最大值和 x 进行比较, 如果 x 小于这个数显然不能再往前走了反之继续;
当然这里 x 需要和这个最大值之后的所有元素进行异或, 利用到结合律我们可以预处理出前缀异或数组来计算;
对于找到某个最高位的最大值我们也可以预处理出一个二维 dp 数组 dp[i][j] 表示前 i 个数 最高位至少为 j 的最大值的位置.
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 void solve () { int n, q; cin >> n >> q; vector<int > w (n + 1 ) , pre (n + 1 ) ; for (int i = 1 ;i <= n;i++) { cin >> w[i]; pre[i] = w[i] ^ pre[i - 1 ]; } vector<vector<int >> dp (n + 1 , vector <int > (30 )); for (int i = 1 ;i <= n;i++) { for (int j = 0 ;j < 30 ;j++) { if ((1 << j) <= w[i]) dp[i][j] = i; else dp[i][j] = dp[i - 1 ][j]; } } auto find = [&] (int x) { int ans = -1 ; for (int i = 0 ;i < 30 ;i++) if ((1 << i) & x) ans = i; return ans; }; while (q--) { int x; cin >> x; int now = n + 1 ; int posmax = find (x); while (true ) { if (posmax == -1 ) break ; int pos = dp[now - 1 ][posmax]; if (pos == 0 ) { now = 1 ; break ; } x ^= (pre[now - 1 ] ^ pre[pos]); if (x < w[pos]) { now = pos + 1 ; break ; } x ^= w[pos]; now = pos; posmax = find (x); } cout << n + 1 - now << " " ; } cout << '\n' ; }