赞
踩
for (int i = 0, j = 0; i < n; i++) {
while (j < i && check(i, j)) j++;
// 每道题目的具体逻辑
}
i
和 j
是否存在单调关系,有的话就可以采用双指针的思想优化代码。#include <iostream> using namespace std; const int N = 100010; int n; int q[N], s[N]; int main() { scanf("%d", &n); for (int i = 0; i < n; i ++ ) scanf("%d", &q[i]); int res = 0; for (int i = 0, j = 0; i < n; i ++ ) { s[q[i]] ++ ; while (j < i && s[q[i]] > 1) s[q[j ++ ]] -- ; res = max(res, i - j + 1); } cout << res << endl; return 0; }
n
的二进制表示中第 k
位数字:n >> k & 1
。
k
位数字移到最后一位,再查看最后一位即可。n
的最后一位(最低位) 1
:lowbit(n) = n & -n
。
n & -n = n & (~n +1)
。1
的个数。思想是,每次找到最后一个 1
的位置,然后把它减掉,统计结果加一,直到该数变成 0
为止。#include <iostream> using namespace std; int main() { int n; scanf("%d", &n); while (n -- ) { int x, s = 0; scanf("%d", &x); for (int i = x; i; i -= i & -i) s ++ ; printf("%d ", s); } return 0; }
a[n]
,一般来讲满足:『
0
≤
a
[
i
]
≤
1
0
9
,
0
≤
n
≤
1
0
5
0≤a[i]≤10^9,0≤n≤10^5
0≤a[i]≤109,0≤n≤105』(即值域很大,个数较少,所以可以理解成是一个稀疏数组)。离散化的作用在于将数组里面的数做一个映射,最简单的是映射到下标值(或下标加一):sort(v.begin(), v.end()); // 排序
v.erase(unique(v.begin(), v.end()), v.end()); // 去重: 将重复元素放在末尾再删除
x
离散化后的值。二分算法参考博客 【Y总/算法基础课/学习笔记】整数二分和浮点数二分算法(Binary Search)(含算法模板)unique()
函数,因此补充一下unique()
函数的实现。思想是双指针算法,将所有不重复的数放到数组最前面,不重复的数满足两个性质:它是第一个出现的,即 i ≠ 0 以及 a[i] ≠ a[i - 1]
。vector<int>::iterator unique(vector<int> &v) {
int j = 0;
for (int i = 0; i < v.size(); i++)
if (!i || v[i] != v[i - 1])
v[j++] = v[i];
// v[0] ~ v[j - 1] 所有v中不重复的数
return v.begin() + j;
}
#include <iostream> #include <vector> #include <algorithm> using namespace std; typedef pair<int, int> PII; const int N = 300010; int n, m; int a[N], s[N]; vector<int> alls; // 储存所有用到的下标值,范围是30万 vector<PII> add, query; // 操作用pair数组存储 // 二分:找到第一个大于等于x的数的下标加一值 int find(int x) { int l = 0, r = alls.size() - 1; while (l < r) { int mid = l + r >> 1; if (alls[mid] >= x) r = mid; else l = mid + 1; } return r + 1; } int main() { cin >> n >> m; for (int i = 0; i < n; i ++ ) { int x, c; cin >> x >> c; add.push_back({x, c}); alls.push_back(x); } for (int i = 0; i < m; i ++ ) { int l, r; cin >> l >> r; query.push_back({l, r}); alls.push_back(l); alls.push_back(r); } // 去重 sort(alls.begin(), alls.end()); alls.erase(unique(alls.begin(), alls.end()), alls.end()); // 处理插入 for (auto item : add) { int x = find(item.first); a[x] += item.second; } // 预处理前缀和 for (int i = 1; i <= alls.size(); i ++ ) s[i] = s[i - 1] + a[i]; // 处理询问 for (auto item : query) { int l = find(item.first), r = find(item.second); cout << s[r] - s[l - 1] << endl; } return 0; }
q
用以维护,再扫描剩余区间 i
,此时只会出现三种以下情况i
在维护区间 q
的内部,则 q
无需改变;i
与维护区间 q
有交集,则 q
需要更新右端点;i
与维护区间 q
没有任何交集,则 q
无需改变,且可以停止扫描了,因为保证了该维护区间与剩余任何区间都不可能有交集;#include <iostream> #include <vector> #include <algorithm> using namespace std; typedef pair<int, int> PII; void merge(vector<PII> &segs) { vector<PII> res; // 区间按左端点排序 sort(segs.begin(), segs.end()); int st = -2e9, ed = -2e9; // 边界区间 for (auto seg : segs) if (ed < seg.first) { if (st != -2e9) res.push_back({st, ed}); st = seg.first, ed = seg.second; } else ed = max(ed, seg.second); if (st != -2e9) res.push_back({st, ed}); // 防止输入区间为空 segs = res; // 更新为合并的区间 } int main() { int n; scanf("%d", &n); vector<PII> segs; for (int i = 0; i < n; i ++ ) { int l, r; scanf("%d%d", &l, &r); segs.push_back({l, r}); } merge(segs); cout << segs.size() << endl; return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。