题目描述
我们定义独特子序列:如果一个序列的某个连续子序列 中恰好包含 个奇数,就称序列 是一个独特子序列。
给定一个长度为 的序列 和一个整数 。请你计算在序列 中一共包含多少个不同的独特子序列,只要序列的左端点和右端点至少有一个不同,就认为是两个不同的独特子序列。
限制:
- 对于 的数据:,
- 对于 的数据:,
- 对于 的数据:,
算法分析
本题难度中等,考察枚举思想与前缀和技巧。考虑以 结尾的 独特子序列
个数,我们需要统计符合条件的下标 的个数,其中 且 这个子序列里的奇数个数恰好为 .
分做法:双重循环分别枚举左端点 和右端点 ,然后再来一重循环统计 之间的奇数个数
时间复杂度:
分做法:在 分做法中需要一重循环统计 之间的奇数个数,可以利用前缀和预处理,然后在 时间之内得到。定义 为 中奇数的个数,则 由 递推而来,即:.
时间复杂度:
分做法:在 分做法中,实际上在统计 的个数。对于这个式子简单移项可得:
所以我们考虑以 结尾的 独特子序列
个数时,只要统计有多少个奇数个数为 的 个数即可。我们只要建立频次数组 cnt
记录 出现的次数,从左往右更新 边计算答案,那么以 结尾的答案 即可在 时间内得到。最后的答案即为所有下标结果的 独特子序列
个数之和。
时间复杂度:
代码实现
#include <bits/stdc++.h> #define rep(i, n) for (int i = 0; i < (n); ++i) using namespace std; using ll = long long; int main() { int n, k; cin >> n >> k; vector<int> a(n); rep(i, n) cin >> a[i]; vector<int> s(n+1); rep(i, n) s[i+1] = s[i] + (a[i]%2 != 0); ll ans = 0; vector<int> cnt(n+1); cnt[0] = 1; for (int i = 1; i <= n; ++i) { if (s[i] >= k) ans += cnt[s[i]-k]; cnt[s[i]]++; } cout << ans << '\n'; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现