牛客寒假算法基础集训营3 I 智乃的密码(二分、尺取)
2022/2/5 1:13:47
本文主要是介绍牛客寒假算法基础集训营3 I 智乃的密码(二分、尺取),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
题目链接
题目大意:
给定字符串 \(s\) 、\(L\) 、\(R\) ,求满足长度为 \([L, R]\) 且至少包含四类字符中的三种的子串数量。
思路:
当固定了区间左端点时,随着右端点向右移动对答案的贡献具有单调性。同样,固定右端点,向右移动左端点,对答案的贡献也有单调性。我们考虑使用尺取。
固定区间的左端点为 \(i\) 时,找可行的右端点的取值范围。
Code:
int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n, L, R; cin >> n >> L >> R; string s; cin >> s; map<int, int> cnt; // 四类字符的数量 auto upd = [&](char ch, int dx) { if (isupper(ch)) { cnt[0] += dx; } else if (islower(ch)) { cnt[1] += dx; } else if (isdigit(ch)) { cnt[2] += dx; } else { cnt[3] += dx; } return; }; ll ans = 0; for (int i = 0, j = 0; i < n; i++) { // [, ) while (j <= n && (cnt[0] > 0) + (cnt[1] > 0) + (cnt[2] > 0) + (cnt[3] > 0) < 3) { if (j < n) upd(s[j], 1); j++; } int l = max(j, i + L); // 此时j是刚好满足出现次数的位置,i + L表示符合条件的右端点至少距离长度为L int r = min(n, i + R); // 右端点不能取越界,且距离最多不能超过R ans += max(0, r - l + 1); upd(s[i], -1); } cout << ans << "\n"; return 0; } /* 11 3 6 11111bAAA** 7 3 6 11111bA */
左端点已经固定,假设此时第一个满足条件的右端点下标为 \(idx\),那么根据单调性在这之后的下标也可以当作右端点。我们可以二分求出第一个满足条件的右端点。这里使用前缀和加速对区间内子串数量的查询。
int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n, L, R; cin >> n >> L >> R; string s; cin >> s; vector<vector<int>> pre(4, vector<int>((int)s.length() + 1)); for (int i = 0; i < n; i++) { for (int j = 0; j < 4; j++) pre[j][i + 1] = pre[j][i]; if (isupper(s[i])) pre[0][i + 1]++; else if (islower(s[i])) pre[1][i + 1]++; else if (isdigit(s[i])) pre[2][i + 1]++; else pre[3][i + 1]++; } auto check = [&](int l, int r) { int cnt = 0; for (int i = 0; i < 4; i++) { cnt += (pre[i][r] - pre[i][l - 1] > 0); } return cnt >= 3; }; ll ans = 0; for (int i = 1; i <= n; i++) { int l = i, r = min(i + R, n + 1), idx = 0; while (l < r) { int mid = (l + r) >> 1; // 找第一个满足条件的右端点 if (check(i, mid)) { idx = mid; r = mid; } else { l = mid + 1; } } if (idx == 0) // 一个满足条件的都没找到 continue; l = max(idx, i + L - 1); r = min(n, i + R - 1); // cerr << "l = " << l << ", r = " << r << endl; ans += max(0, r - l + 1); } cout << ans << "\n"; return 0; }
这篇关于牛客寒假算法基础集训营3 I 智乃的密码(二分、尺取)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南