Codeforces Round 962(Div.3) (A-E) A.Legs 签到题,直接放代码
Code: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include<bits/stdc++.h> #define endl '\n' using i64 = long long; using namespace std; signed main(){ std::ios::sync_with_stdio(false);cin.tie(0); int t; cin >> t; while(t--){ int n, ans; cin >> n; if(n==2) ans = 1; else if(n%4==0) ans = n / 4; else ans = n / 4 + 1; cout << ans << endl; } return 0; }
B.Scale 简单模拟题,同上,直接放代码
Code: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include<bits/stdc++.h> #define endl '\n' using i64 = long long; using namespace std; signed main(){ std::ios::sync_with_stdio(false);cin.tie(0); int t; cin >> t; while(t--){ int n, k; cin >> n >> k; vector<string> s(n + 1); for (int i = 1; i <= n;i++) cin >> s[i], s[i] = " " + s[i]; for (int i = 1; i <= n; i += k){ for (int j = 1; j <= n; j += k) cout << s[i][j]; cout << endl; } } return 0; }
C.Sort(前缀和) 时间复杂度:$O(26 \cdot n)$ 题意就是判断区间内不同字符的个数,注意$n,q$的范围均高达$2 \cdot 10^5$,所以使用前缀和预处理 维护各个字母的前缀和,并离线 处理询问即可。
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 #include<bits/stdc++.h> #define endl '\n' using i64 = long long; using namespace std; signed main(){ std::ios::sync_with_stdio(false);cin.tie(0); int t; cin >> t; while(t--){ int n, q; cin >> n >> q; vector<vector<int>> pre1(n + 1, vector<int>(30)); vector<vector<int>> pre2(n + 1, vector<int>(30)); string a, b; cin >> a >> b; a = " " + a, b = " " + b; for (int i = 1; i <= n; i++){ for (int j = 1; j <= 26;j++){ pre1[i][j] = pre1[i - 1][j]; pre2[i][j] = pre2[i - 1][j]; } pre1[i][a[i] - 'a' + 1]++; pre2[i][b[i] - 'a' + 1]++; } while(q--){ int l, r, ans = 0; cin >> l >> r; for (int i = 1; i <= 26;i++) ans += min(pre1[r][i] - pre1[l - 1][i], pre2[r][i] - pre2[l - 1][i]); //区间内相同字符数量 ans = r - l + 1 - ans; cout << ans << endl; } } return 0; }
D.Fun(枚举,数学) 时间复杂度:$O(n \ln n)$ 题意 给定两个整数$n$与$x$,寻找数对$(a,b,c)$的数量 ,其中$ab+ac+bc \le n$以及$a+b+c \le x$。注意,数对$(a,b,c)$中$a,b,c$三者相互独立(顺序固定)且均是正整数 .
数据范围
$1 \le n,x \le 10^6$
$\sum n, \sum x \le 10^6$
思路 首先从暴力枚举的角度统计数量,三层循环一定是超时的,我们退而求其次,考虑只枚举$a,b$;因为有限定条件$ab \le n$且$a+b \le x$,所以两层循环($i,j$分别代表$a,b$)枚举$a,b$的复杂度为$j+ \frac{j}{2}+ \frac{j}{3}+…+1$,调和级数 的复杂度趋向$O(n\cdot \ln n)$,对于题设中$1e6$的范围上限显然是可以接受的. 通过枚举的方式,每次循环$a,b$的值,所以$c$的正整数数量就是数对数量 。由于$a,b$已知,由题设中两条不等式可推断:
$c \le \dfrac{n-ab}{a+b}$
$c \le x-a-b$
综上,$c$的正整数数量就是$min(\dfrac{n-ab}{a+b},x-a-b)$.
Code: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include<bits/stdc++.h> #define endl '\n' using i64 = long long; using namespace std; signed main(){ std::ios::sync_with_stdio(false);cin.tie(0); int t; cin >> t; while(t--){ int n, x; cin >> n >> x; int mn = min(n, x); i64 ans = 0; for (int i = 1; i < mn;i++) //枚举a for (int j = 1; i * j < n && i + j < x;j++) //枚举b ans += min(x - i - j, (n - i * j) / (i + j)); cout << ans << endl; } return 0; }
E.Decode 时间复杂度:$O(n \log_2 n)$ 题意 给定一个二进制 字符串,对于每对整数$(l,r)(1 \le l \le r \le n)$,计算连续子串 $s_x s_{x+1}…s_y$中0的数量等于1的数量 的数对数量$(x,y)(l \le x \le y \le r)$。最后的答案取$1e9+7$的模.
数据范围
$1 \le |s| \le 2 \cdot 10^5$
$\sum |s| \le 2 \cdot 10^5$
思路 对于子串数量的统计我们可以进行转化:求任意区间$(l,r)$中满足条件的子串$(x,y)$ $\Rightarrow$ 求满足条件的子串${(x,y)}$的区间$(l,r)$$(l \le x,r \ge y)$ 的方案数 。 所以问题转化为寻找所有区间数量0和1相同的子串 ,若当前子串为$(x,y)$,字符串长度为$n$,那么合法的$(l,r)$的方案总数量显然是$x\times(n-y+1)$(乘法原理 ). 寻找区间0和1数量相等的子串,经典思路就是将所有0置负 ,那么区间数量相等等价于区间和为0 ,即前缀和$pre[r]=pre[l-1]$;对于每一个枚举到的$l$,我们都需要找到右边所有 满足区间和为0的$r$,所以需要使用维护一个后缀和 ,所以对于每一位枚举到的$l$,它对答案的贡献为$l*suf$.
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 #include<bits/stdc++.h> #define endl '\n' using i64 = long long; using namespace std; const i64 p = 1e9 + 7; signed main(){ std::ios::sync_with_stdio(false);cin.tie(0); int t; cin >> t; while(t--){ string s; cin >> s; int n = s.length(); s = " " + s; vector<int> pre(n + 1); map<int, i64> suf; for (int i = 1; i <= n;i++){ pre[i] = pre[i - 1]; pre[i] += (s[i] == '1' ? 1 : -1); } suf[pre[n]] = 1; i64 ans = 0; for (int i = n - 1; i >= 1;i--){ //cout << i << ' ' << suf[pre[i]] << endl; ans = (ans + 1LL * i * suf[pre[i - 1]] % p) % p; suf[pre[i]] += n - i + 1; //边遍历边统计 } cout << ans << endl; } return 0; }