D - Ghost Ants
https://atcoder.jp/contests/abc360/tasks/abc360_d
题意:给定n个箭头,有往左的有往右的,问有多少个有序对(i, j)在时间T内会相交。每个时间点移动一个单位。
思路:考虑所有往右的箭头,那么可以求出可以移动的最右边的坐标,然后找出数组中所有小于这个坐标的箭头即可。
总结:第一眼看感觉是动态线段树,带了负数的值的区间查询。
然后看了一眼数组有序,而且要求是有序对,以为是从当前下标的i开始,去后面找所有符合条件的箭头。(其实是这样的,不过如果只找往左的方向的箭头的话,就会漏掉一些有序对,比如i<j ,i往左j往右,但是a[i]在a[j]右边)。
最后用了fenwick + 离散化,跑的速度也挺快。
就是被有序对误导了,有序对+找向左的箭头!=》在右边找向左的箭头。。
void solve() {
int n, t;
cin >> n >> t;
string s;
cin >> s;
vector<int> a(n);
vector<long long> b{-INF_LL};
for (int i = 0; i < n; ++i){
cin >> a[i];
b.push_back(a[i]);
if (s[i] == '1'){
b.push_back(a[i] + 2ll * t);
}
}
sort(b.begin(), b.end());
b.erase(unique(b.begin(), b.end()), b.end());
int m = b.size();
FenwickTree ft(m + 1);
for (int i = 0; i < n; ++i){
if (s[i] == '0'){
int p = lower_bound(b.begin(), b.end(), a[i]) - b.begin();
ft.update(p, 1);
}
}
long long ans = 0;
for (int i = 0; i < n; ++i){
if (s[i] == '1'){
int p = prev(upper_bound(b.begin(), b.end(), 1ll * a[i] + 2 * t)) - b.begin();
int q = lower_bound(b.begin(), b.end(), 1ll * a[i]) - b.begin();
ans += ft.query(q + 1, p);
}
}
cout << ans << '\n';
}
有模板写题就是好用,只要维护固定的几个函数即可。
模板放在了下面的仓库,如果有用,请点进去点个star。
https://github.com/yxc-s/programming-template/tree/master
该仓库是一个新仓库,旨在打造一个通用的C++算法编程竞赛模板,包含数据结构,数论等各种实用的算法编程模板。如果您使用的语言不是C++,也可以将对应的代码实现翻译成其他语言来使用。