A. Skibidus and Amog’u 题目链接:https://codeforces.com/contest/2065/problem/A
没有什么特别的,根据题目直接模拟即可
1 2 3 4 5 6 7 8 void solve () { string s; cin >> s; int len = s.length (); for (int i = 0 ;i < len - 2 ;i++) cout << s[i]; cout << "i" << '\n' ; }
B. Skibidus and Ohio 题目链接:https://codeforces.com/contest/2065/problem/B
我们发现如果至少存在一组使得 s[i] == s[i + 1] 那么我们就可以一直操作直到剩最后一个字母
1 2 3 4 5 6 7 8 9 10 11 12 13 14 void solve () { string s; cin >> s; int len = s.length (); for (int i = 0 ;i < len - 1 ;i++) { if (s[i] == s[i + 1 ]) { cout << 1 << '\n' ; return ; } } cout << len << '\n' ; }
C. Skibidus and Fanum Tax (C1,C2) 题目链接:https://codeforces.com/contest/2065/problem/C2
由于对每个 a[i] 都可以独立地使用任意一个 b[j] (且可以重复使用),因此对于每个 i,如果我们选择操作,
实际上可以得到任意形如 b − a[i] 的数,其中 b 来自数组 b;
而我们的目标是 “给后面的数留出空间”;因此在满足”至少不比前一个数小”的前提下,越小越好.
一种自然的思路是动态规划:
1.不操作: 若 a[i] >= dp[i - 1], 则可以令 dp[i] = a[i].
2.操作: 如果存在某个b使得操作后的值满足b >= dp[i - 1] + a[i]那么我们可以从数组 b 中选择满足条件的最小值b(我们记为b*), 这样得到的操作结果是 dp[i] = b*-a[i].
最终, 若对某个位置 i 上, 两种选择都不满足条件 (即都无法使 v[i] >= dp[i - 1]),
则说明无法构造出一个非递减序列;
否则, 最后存在一种方案使得整个序列非递减.
对于操作选项, 我们需要找到满足 b >= dp[i - 1] + a[i] 的最小的 b ,
因此我们可以先对数组 b 排序, 再用二分查找来寻找下界.
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 void solve () { int n, m; cin >> n >> m; vector<int > a (n + 1 ) , b (m + 1 ) ; for (int i = 1 ;i <= n;i++) cin >> a[i]; for (int i = 1 ;i <= m;i++) cin >> b[i]; sort (b.begin (), b.end ()); int dp = -INF; for (int i = 1 ;i <= n;i++) { int sen = INF; if (a[i] >= dp) sen = a[i]; int mid = dp + a[i]; auto pos = lower_bound (b.begin () + 1 , b.end (), mid); if (pos != b.end ()) sen = min (sen, *pos - a[i]); if (sen == INF) { cout << "NO\n" ; return ; } dp = sen; } cout << "YES\n" ; }
D. Skibidus and Sigma 题目链接:https://codeforces.com/contest/2065/problem/D
由题目所得, 分数的构成是由前缀和来决定, 所以贪心的想法就是把前缀和大的数组放在前面,这样我们就能最大化分数.
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 void solve () { int n, m; cin >> n >> m; vector<vector<int >> v (n + 1 , vector <int > (m + 1 )); vector<PII> sen; for (int i = 1 ;i <= n;i++) { ll sum = 0 ; for (int j = 1 ;j <= m;j++) { cin >> v[i][j]; sum += v[i][j]; } sen.push_back ({sum, i}); } sort (sen.begin (), sen.end (), greater <PII> ()); ll ans = 0 ; ll cnt = 0 ; for (auto [sum, pos] : sen) { for (int j = 1 ;j <= m;j++) { cnt += v[pos][j]; ans += cnt; } } cout << ans << '\n' ; }
E. Skibidus and Rizz 题目链接:https://codeforces.com/contest/2065/problem/E
根据题目, 我们需要关注几个点:
现在我们假设 n > m:
我们可以先输出 k 个0, 再输出 k - (n - m) 个 1 这样操作后 0 和 1 的剩余个数就会一样;
从前面我们知道 abs(n - m) <= k 那么如果 n - m < k 我们就可以直接 101010 这样交替构造;
如果 n - m == k 则 此时只能 010101 这样构造
反之如果 n < m 同理
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 void solve () { int n, m, k; cin >> n >> m >> k; if (abs (n - m) > k) { cout << -1 << '\n' ; return ; } auto f = [&] (char tar, int num1, int num2) -> string { string s = "" ; for (int i = 0 ;i < k;i++) s.push_back (tar); char sen = (tar == '1' ? '0' : '1' ); for (int i = 0 ;i < k - (num1 - num2);i++) s.push_back (sen); int len = num1 - k; if (num1 - num2 < k) { for (int i = 0 ;i < len;i++) { s.push_back (tar); s.push_back (sen); } } else { for (int i = 0 ;i < len;i++) { s.push_back (sen); s.push_back (tar); } } return s; }; if (n >= m) { if (n < k) { cout << -1 << '\n' ; return ; } string ans = f ('0' , n, m); cout << ans << '\n' ; } else { if (m < k) { cout << -1 << '\n' ; return ; } string ans = f ('1' , m, n); cout << ans << '\n' ; } }
F. Skibidus and Slay 题目链接:https://codeforces.com/contest/2065/problem/F
首先以一个点为中心向四周扩散这种也符合题目要求的简单路径;
假设某条边所连两个点对应值相等,此时为满足条件的最短的路径;
如果并不相等那么我们可以依次判断每个点的所有连边, 例如此时顶点为3(值与后边不同)和他所连的两个点为1, 2值均为5
此时 1 <- 3 -> 2 是满足条件的 我们可以记录对应值出现的个数, 如果个数大于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 void solve () { int n; cin >> n; vector<int > a (n + 1 ) ; for (int i = 1 ;i <= n;i++) cin >> a[i]; vector<vector<int >> edge (n + 1 , vector <int > ()); vector<int > ans (n + 1 ) ; for (int i = 0 ;i < n - 1 ;i++) { int u, v; cin >> u >> v; edge[u].push_back (v); edge[v].push_back (u); if (a[u] == a[v]) ans[a[u]] = 1 ; } for (int i = 1 ;i <= n;i++) { map<int , int > mp; for (auto c : edge[i]) mp[a[c]]++; for (auto [c, v] : mp) { if (v > 1 ) ans[c] = 1 ; } } for (int i = 1 ;i <= n;i++) cout << ans[i]; cout << '\n' ; }
G. Skibidus and Capping 题目链接:https://codeforces.com/contest/2065/problem/G
数论题不做啦