Codeforces Round 970 (Div. 3) ABCDEFGH

lulaalu·2024-09-03 21:02·216 次阅读

Codeforces Round 970 (Div. 3) ABCDEFGH

来源:Codeforces Round 970 (Div. 3)

  • 头文件
Copy
#include <bits/stdc++.h> using namespace std; #define YES "YES" #define NO "NO" #define Yes "Yes" #define No "No" #define F first #define S second #define int long long #define ull unsigned long long #define endl "\n" #define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); #define rep(i, j, k) for (int i = (j); i < (k); i++) #define all(x) x.begin(), x.end() #define vi vector<int> #define pii pair<int, int>

A. Sakurako's Exam#

思路#

看1能不能来抵消2,如果没有1就看2的数量,有1就看是奇数还是偶数,如果是偶数就能抵消2

代码#

Copy
string solve() { int a, b; cin >> a >> b; if (a == 0) { if (b % 2 == 0) return YES; else return NO; } if (a % 2 == 1) { return NO; } else { return YES; } } signed main() { IOS; int t = 1; cin >> t; while (t--) { cout << solve() << endl; } return 0; }

B. Square or Not#

思路#

先看长度符不符合要求

再特判一下有没有0的情况,除n=4外其他没有0都输出No

然后根据n求边长,枚举所有点

代码#

Copy
string s; string solve() { int n; cin >> n >> s; if ((int)sqrt(n) * (int)sqrt(n) != n) { return No; } if (s.find('0') == string::npos) { if (n == 4) return Yes; else return No; } int a = (int)sqrt(n); for (int i = 0; i < a; i++) { for (int j = 0; j < a; j++) { char ch = s[i * a + j]; char sch;// 应该是1或0 if (i == 0 || j == 0 || i == a - 1 || j == a - 1) sch = '1'; else sch = '0'; if (ch != sch) {// 实际与理论比较一下 return No; } } } return Yes; } signed main() { IOS; int t = 1; cin >> t; while (t--) { cout << solve() << endl; } return 0; }

C. Longest Good Array#

思路#

最优情况就是从 l 开始,每个差值都差 1

然后开头到结尾的就相差 1+2+3+... 所以用求和公式或者一个数组就行

代码#

Copy
const int N = 5e4; int f[N]; int solve() { int l, r; cin >> l >> r; int len = r - l + 1; int ans = lower_bound(f, f + N, len) - f; return ans; } void pre() { f[0] = 0; f[1] = 1; for (int i = 2; i < N; i++) f[i] = f[i - 1] + i; } signed main() { IOS; int t = 1; pre(); cin >> t; while (t--) { cout << solve() << endl; } return 0; }

D. Sakurako's Hobby#

思路#

并查集,因为是全排列,就是好几个圈圈,一开始还以为会出现环上带线,那就麻烦了

代码#

Copy
const int N = 2e5 + 10; string s; int fa[N]; int ans[N]; // 并查集 int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); } void merge(int x, int y) { fa[find(x)] = find(y); } void solve() { int n; cin >> n; rep(i, 1, n + 1) { fa[i] = i; ans[i] = 0; } rep(i, 1, n + 1) { int tmp; cin >> tmp; merge(i, tmp); } cin >> s; rep(i, 0, n) { // s的0表示黑色 if (s[i] == '0') ans[find(fa[i + 1])]++; } rep(i, 1, n + 1) cout << ans[find(fa[i])] << " "; cout << endl; }

E. Alternating String#

思路#

如果是偶数就把奇数上最多的保留,偶数位上最多的字母保留

如果是奇数,就维护前缀和,然后遍历每个位置

删除当前位置后

如果想算奇数上的 a 字母,就是当前位置前的奇数位上的 a 的数量+当前位置后的偶数位上的 a 的数量

把奇数和偶数上的最大数算出来,再跟目前的最大数比较,和较大的更优

代码#

Copy
int n; string s; const int N = 2e5 + 10; int sum[26][2][N];// sum[i][j][k] 从0到k位,奇(1)/偶(0)位上字母i的数量 int solve() { cin >> n >> s; if (n % 2 == 0) {// 不删,算数量就行 map<int, int> ji_mp; map<int, int> ou_mp; for (int i = 0; i < n; i += 2) ou_mp[s[i] - 'a']++; for (int i = 1; i < n; i += 2) ji_mp[s[i] - 'a']++; int ji_mx = 0; int ou_mx = 0; for (int i = 0; i < 26; i++) { ji_mx = max(ji_mx, ji_mp[i]); ou_mx = max(ou_mx, ou_mp[i]); } return n - ji_mx - ou_mx; } // 初始化 rep(i, 0, 26) { rep(j, 0, n + 2) { sum[i][0][j] = 0; sum[i][1][j] = 0; } } // 算累加 for (int i = 0; i < n; i++) { if (i % 2 == 0) sum[s[i] - 'a'][0][i + 1] = 1; else sum[s[i] - 'a'][1][i + 1] = 1; for (int j = 0; j < 26; j++) { sum[j][0][i + 1] += sum[j][0][i]; sum[j][1][i + 1] += sum[j][1][i]; } } int ji_mx = 0; int ou_mx = 0; for (int i = 1; i <= n; i++) { int tjimx = 0, toumx = 0; // 求最大 for (int j = 0; j < 26; j++) { int ji_num = sum[j][1][i - 1] + (sum[j][0][n] - sum[j][0][i]); int ou_num = sum[j][0][i - 1] + (sum[j][1][n] - sum[j][1][i]); tjimx = max(tjimx, ji_num); toumx = max(toumx, ou_num); } // 比较当前位置的最大和总的最大 if (tjimx + toumx > ji_mx + ou_mx) { ji_mx = tjimx; ou_mx = toumx; } } return n - 1 - ji_mx - ou_mx + 1; }

F. Sakurako's Box#

思路#

[1,2,3,4,5] 为例,暴力会超时,所以维护后缀和,

1(2+3+4+5)
2(3+4+5)
3(4+5)
45

然后总共抽 (n1)n2 次,这题大概主要是考逆元

代码#

Copy
// int用long long来替,避免溢出 const int MOD = 1e9 + 7; const int N = 2e5 + 10; int ksm(int a, int b) { int res = 1; while (b) { if (b & 1) res = res * a % MOD; a = a * a % MOD; b >>= 1; } return res; } int sum[N]; // 后缀和 int a[N]; int solve() { int n; cin >> n; rep(i, 1, n + 1) { cin >> sum[i]; a[i] = sum[i]; } for (int i = n - 1; i >= 1; i--) { sum[i] += sum[i + 1]; sum[i] %= MOD; } int s = 0; rep(i, 1, n) { int tmp = (a[i] * sum[i + 1]) % MOD; s = (s + tmp) % MOD; } int k = ((n - 1) * n / 2) % MOD; if (s % k == 0) return s / k; return (ksm(k, MOD - 2) * s) % MOD; }

G. Sakurako's Task#

思路#

加来减去这种题,很可能跟gcd有关系,

首先分析一下,所有数的gcd一定小于等于最小值,比如gcd=2时,n=5,那么一定可以通过这个2把数组变成 [0,2,4,6,8] 这种,在这种序列下的答案是最大的

特判一下n=1的情况

代码#

Copy
int n, k; int a[200005]; int solve() { cin >> n >> k; rep(i, 1, n + 1) cin >> a[i]; if (n == 1) { if (k <= a[1]) return k - 1; else return k; } // 求所有的gcd int GCD = 0; rep(i, 1, n + 1) GCD = __gcd(GCD, a[i]); // 如果k很大 if ((n - 1) * (GCD - 1) < k) return n - 1 + k; int re = (k - 1) / (GCD - 1); // region /* 如gcd=3时,数组是[0,3,6,9] ,k=1或2,位于0到3之间,k=4或5,位于3到6之间 相当于位于区域0和区域1,每个区域大小是gcd-1 */ return re * GCD + (k - 1) % (GCD - 1) + 1; }

H. Sakurako's Test#

思路#

最小中位数,就是把所有值都尽量缩小,那就所有值取%x

二分答案,答案一定在0到x之间

每次check查看比mid小的值的数量,如果数量过多说明mid过大,需要减小,反之需要增加

以下是需要注意的:

  • 这个二分,有时候是r-1,l+1,有时候又不用,所以我一般是记录答案,如果mid跟答案一样就break,基本没问题,也不用反复尝试
  • 这个check,如果每次遍历,经过亲身经历,会超时,所以需要记录数量,然后把每个%x后比mid小的区间加上,就是需要一个前缀和来加速
  • 本题会重复询问同一个值,需要记忆化答案

代码#

Copy
int cnt[200010]; int n; bool check(int mid, int q) { int small = 0; small += cnt[mid - 1]; for (int i = 1; 1; i++) { if (mid - 1 + q * i >= n) { if (i * q - 1 <= n) small += cnt[n] - cnt[i * q - 1]; break; } small += cnt[mid - 1 + q * i] - cnt[i * q - 1]; } if (small <= n / 2) return true; else return false; } int t; pii ans[100001];// 记忆化答案 void solve() { int m; cin >> n >> m; rep(i, 0, n + 1) cnt[i] = 0; rep(i, 0, n) { int x; cin >> x; cnt[x]++; } rep(i, 1, n + 1) cnt[i] += cnt[i - 1]; rep(i, 0, m) { int q; cin >> q; if (ans[q].F == t) { cout << ans[q].S << " "; continue; } int l = 0, r = q; int mid; int res = 0; while (l < r) { mid = (l + r) / 2; if (check(mid, q)) {// 不需要思考,莽上去就行 if (res == mid) break; res = mid; l = mid; } else { r = mid; } } cout << res << " "; ans[q] = {t, res}; } cout << endl; } signed main() { IOS; for (int i = 0; i < 100001; i++) { ans[i] = {-1, -1}; } cin >> t; while (t--) solve(); return 0; }
posted @   lulaalu  阅读(216)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
目录