CF1045G AI robots题解
题目链接:洛谷 或者 CF
本题考虑转化为 cdq 分治模型
对于 cdq 分治来说,只需要考虑左边对右边的影响,那我们要考虑该怎样设置第一维度的左右对象。很显而易见的是抛开
考虑上述两个条件如何转化为一个条件,我们注意到如果有
简单证明就是有两个机器人,它们都处在各自圆心处在数轴上,各自有个探测半径,现在要求它们的圆心都处于对方的园内。很显而易见的有:
那么我们就能把双方影响,变为只有一方影响另一方了,符合 cdq 模型。考虑哪个放左哪个放右?右边是受左边影响计算的。考虑计算某个
现在考虑
当前查询点和其他点的
cdq 分治的题型常常有这么几步,考虑外层如何转化为单个对象对单个对象有影响,从而确定左右之分,受影响和影对象。内存因为基于归并排序的结构,所以常常可以让其中一维有序,有序就具备了单调性,常常可以考虑构建双指针或者其他单调算法。最后再配上一个查询类的数据结构就行了,常常是计数类问题,所以可以考虑树状数组。
算法框架
首先我们最终使用树状数组查询探测范围,所以需要考虑离散化,我用的哈希表进行离散化,结果发现 gp_hash_table 被卡哈希了,试了下 unordered_map 或者 cc_hash_table 没问题,当然cf 上非必要还是考虑使用 map 代替哈希表功能。当然也可以用二分离散化。
其次,外层需要对探测范围排序,由于小的探测范围作为被查询对象,需要放右边,所以逆序排序就好了。最后在每次 merge 时将
参照代码
#include <bits/stdc++.h> //#pragma GCC optimize("Ofast,unroll-loops") // #define isPbdsFile #ifdef isPbdsFile #include <bits/extc++.h> #else #include <ext/pb_ds/priority_queue.hpp> #include <ext/pb_ds/hash_policy.hpp> #include <ext/pb_ds/tree_policy.hpp> #include <ext/pb_ds/trie_policy.hpp> #include <ext/pb_ds/tag_and_trait.hpp> #include <ext/pb_ds/hash_policy.hpp> #include <ext/pb_ds/list_update_policy.hpp> #include <ext/pb_ds/assoc_container.hpp> #include <ext/pb_ds/exception.hpp> #include <ext/rope> #endif using namespace std; using namespace __gnu_cxx; using namespace __gnu_pbds; typedef long long ll; typedef long double ld; typedef pair<int, int> pii; typedef pair<ll, ll> pll; typedef tuple<int, int, int> tii; typedef tuple<ll, ll, ll> tll; typedef unsigned int ui; typedef unsigned long long ull; typedef __int128 i128; #define hash1 unordered_map #define hash2 gp_hash_table #define hash3 cc_hash_table #define stdHeap std::priority_queue #define pbdsHeap __gnu_pbds::priority_queue #define sortArr(a, n) sort(a+1,a+n+1) #define all(v) v.begin(),v.end() #define yes cout<<"YES" #define no cout<<"NO" #define Spider ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr); #define MyFile freopen("..\\input.txt", "r", stdin),freopen("..\\output.txt", "w", stdout); #define forn(i, a, b) for(int i = a; i <= b; i++) #define forv(i, a, b) for(int i=a;i>=b;i--) #define ls(x) (x<<1) #define rs(x) (x<<1|1) #define endl '\n' //用于Miller-Rabin [[maybe_unused]] static int Prime_Number[13] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}; template <typename T> int disc(T* a, int n) { return unique(a + 1, a + n + 1) - (a + 1); } template <typename T> T lowBit(T x) { return x & -x; } template <typename T> T Rand(T l, T r) { static mt19937 Rand(time(nullptr)); uniform_int_distribution<T> dis(l, r); return dis(Rand); } template <typename T1, typename T2> T1 modt(T1 a, T2 b) { return (a % b + b) % b; } template <typename T1, typename T2, typename T3> T1 qPow(T1 a, T2 b, T3 c) { a %= c; T1 ans = 1; for (; b; b >>= 1, (a *= a) %= c)if (b & 1)(ans *= a) %= c; return modt(ans, c); } template <typename T> void read(T& x) { x = 0; T sign = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-')sign = -1; ch = getchar(); } while (isdigit(ch)) { x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar(); } x *= sign; } template <typename T, typename... U> void read(T& x, U&... y) { read(x); read(y...); } template <typename T> void write(T x) { if (typeid(x) == typeid(char))return; if (x < 0)x = -x, putchar('-'); if (x > 9)write(x / 10); putchar(x % 10 ^ 48); } template <typename C, typename T, typename... U> void write(C c, T x, U... y) { write(x), putchar(c); write(c, y...); } template <typename T11, typename T22, typename T33> struct T3 { T11 one; T22 tow; T33 three; bool operator<(const T3 other) const { if (one == other.one) { if (tow == other.tow)return three < other.three; return tow < other.tow; } return one < other.one; } T3() { one = tow = three = 0; } T3(T11 one, T22 tow, T33 three) : one(one), tow(tow), three(three) { } }; template <typename T1, typename T2> void uMax(T1& x, T2 y) { if (x < y)x = y; } template <typename T1, typename T2> void uMin(T1& x, T2 y) { if (x > y)x = y; } constexpr int N = 1e5 + 10; set<int> t; hash3<int, int> mp; int n, K; ll ans; int mx; int bit[N << 2]; struct Query { int pos, R, l, r; int q; } node[N]; inline void add(int x, const int val) { for (; x <= mx; x += lowBit(x))bit[x] += val; } inline int query(int x) { int ans = 0; for (; x; x -= lowBit(x))ans += bit[x]; return ans; } inline int queryLR(const int L, const int R) { return query(R) - query(L - 1); } //按探测范围降序排序 inline bool cmpLen(const Query& x, const Query& y) { return x.R > y.R; } Query tmp[N]; //q有序数组合并 inline void merge(const int L, const int mid, const int R) { int cnt = L; int i = L, j = mid + 1; while (i <= mid and j <= R)tmp[cnt++] = node[i].q <= node[j].q ? node[i++] : node[j++]; while (i <= mid)tmp[cnt++] = node[i++]; while (j <= R)tmp[cnt++] = node[j++]; forn(i, L, R)node[i] = tmp[i]; } inline void cdq(const int L, const int R) { const int mid = L + R >> 1; if (L == R)return; cdq(L, mid); cdq(mid + 1, R); int l = L, r = L - 1; //双指针找[q-K,q+K]范围内的所有圆心,加入树状数组 forn(curr, mid+1, R) { auto [pos,R,queryL,queryR,q] = node[curr]; while (l <= mid and q - K > node[l].q)add(node[l++].pos, -1); while (r < mid and node[r + 1].q <= q + K)add(node[++r].pos, 1); ans += queryLR(queryL, queryR); } forn(i, l, r)add(node[i].pos, -1); merge(L, mid, R); //使q有序 } inline void solve() { cin >> n >> K; forn(i, 1, n) { auto& [pos,R,_1,_2,q] = node[i]; cin >> pos >> R >> q; t.insert(pos); t.insert(pos + R); t.insert(pos - R); } for (auto v : t)mp[v] = ++mx; //离散化 forn(i, 1, n)node[i].l = mp[node[i].pos - node[i].R], node[i].r = mp[node[i].pos + node[i].R], node[i].pos = mp[node[i].pos]; sort(node + 1, node + n + 1, cmpLen); cdq(1, n); cout << ans; } signed int main() { Spider //------------------------------------------------------ int test = 1; // read(test); // cin >> test; forn(i, 1, test)solve(); // while (cin >> n, n)solve(); // while (cin >> test)solve(); }
优化常数代码
#include <bits/stdc++.h> //#pragma GCC optimize("Ofast,unroll-loops") // #define isPbdsFile #ifdef isPbdsFile #include <bits/extc++.h> #else #include <ext/pb_ds/priority_queue.hpp> #include <ext/pb_ds/hash_policy.hpp> #include <ext/pb_ds/tree_policy.hpp> #include <ext/pb_ds/trie_policy.hpp> #include <ext/pb_ds/tag_and_trait.hpp> #include <ext/pb_ds/hash_policy.hpp> #include <ext/pb_ds/list_update_policy.hpp> #include <ext/pb_ds/assoc_container.hpp> #include <ext/pb_ds/exception.hpp> #include <ext/rope> #endif using namespace std; using namespace __gnu_cxx; using namespace __gnu_pbds; typedef long long ll; typedef long double ld; typedef pair<int, int> pii; typedef pair<ll, ll> pll; typedef tuple<int, int, int> tii; typedef tuple<ll, ll, ll> tll; typedef unsigned int ui; typedef unsigned long long ull; typedef __int128 i128; #define hash1 unordered_map #define hash2 gp_hash_table #define hash3 cc_hash_table #define stdHeap std::priority_queue #define pbdsHeap __gnu_pbds::priority_queue #define sortArr(a, n) sort(a+1,a+n+1) #define all(v) v.begin(),v.end() #define yes cout<<"YES" #define no cout<<"NO" #define Spider ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr); #define MyFile freopen("..\\input.txt", "r", stdin),freopen("..\\output.txt", "w", stdout); #define forn(i, a, b) for(int i = a; i <= b; i++) #define forv(i, a, b) for(int i=a;i>=b;i--) #define ls(x) (x<<1) #define rs(x) (x<<1|1) #define endl '\n' //用于Miller-Rabin [[maybe_unused]] static int Prime_Number[13] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}; template <typename T> int disc(T* a, int n) { return unique(a + 1, a + n + 1) - (a + 1); } template <typename T> T lowBit(T x) { return x & -x; } template <typename T> T Rand(T l, T r) { static mt19937 Rand(time(nullptr)); uniform_int_distribution<T> dis(l, r); return dis(Rand); } template <typename T1, typename T2> T1 modt(T1 a, T2 b) { return (a % b + b) % b; } template <typename T1, typename T2, typename T3> T1 qPow(T1 a, T2 b, T3 c) { a %= c; T1 ans = 1; for (; b; b >>= 1, (a *= a) %= c) if (b & 1) (ans *= a) %= c; return modt(ans, c); } template <typename T> void read(T& x) { x = 0; T sign = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') sign = -1; ch = getchar(); } while (isdigit(ch)) { x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar(); } x *= sign; } template <typename T, typename... U> void read(T& x, U&... y) { read(x); read(y...); } template <typename T> void write(T x) { if (typeid(x) == typeid(char)) return; if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 ^ 48); } template <typename C, typename T, typename... U> void write(C c, T x, U... y) { write(x), putchar(c); write(c, y...); } template <typename T11, typename T22, typename T33> struct T3 { T11 one; T22 tow; T33 three; bool operator<(const T3 other) const { if (one == other.one) { if (tow == other.tow) return three < other.three; return tow < other.tow; } return one < other.one; } T3() { one = tow = three = 0; } T3(T11 one, T22 tow, T33 three) : one(one), tow(tow), three(three) { } }; template <typename T1, typename T2> void uMax(T1& x, T2 y) { if (x < y) x = y; } template <typename T1, typename T2> void uMin(T1& x, T2 y) { if (x > y) x = y; } struct Hash { static uint64_t splitmix64(uint64_t x) { x += 0x9e3779b97f4a7c15; x = (x ^ x >> 30) * 0xbf58476d1ce4e5b9; x = (x ^ x >> 27) * 0x94d049bb133111eb; return x ^ x >> 31; } static size_t get(const uint64_t x) { static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count(); return splitmix64(x + FIXED_RANDOM); } template <typename T> size_t operator()(T x) const { return get(std::hash<T>()(x)); } template <typename F, typename S> size_t operator()(pair<F, S> p) const { return get(std::hash<F>()(p.first)) ^ std::hash<S>()(p.second); } }; constexpr int N = 1e5 + 10; int tot, t[N << 2]; hash2<int, int, Hash> mp; int n, K; ll ans; int bit[N << 2]; struct Query { int pos, R, l, r; int q; bool operator<(const Query other) const { return q < other.q; } } node[N]; inline void add(int x, const int val) { for (; x <= tot; x += lowBit(x)) bit[x] += val; } inline int query(int x) { int ans = 0; for (; x; x -= lowBit(x)) ans += bit[x]; return ans; } inline int queryLR(const int L, const int R) { return query(R) - query(L - 1); } namespace fasI { constexpr int BF_SIZE = 1 << 12; bool IOerr = false; inline char nc() { static char buf[BF_SIZE], *p1 = buf + BF_SIZE, *pend = buf + BF_SIZE; if (p1 == pend) { p1 = buf; pend = buf + fread(buf, 1, BF_SIZE,stdin); if (pend == p1) { IOerr = true; return -1; } } return *p1++; } inline bool bla(const char ch) { return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'; } template <typename T> void Rd(T& x) { char ch; while (bla(ch = nc())); T sign = 1; if (ch == '-') sign = -1, ch = nc(); for (x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0'); x *= sign; } template <typename T, typename... U> void Rd(T& x, U&... y) { Rd(x); Rd(y...); } #undef BF_SIZE } using namespace fasI; //按探测范围降序排序 inline bool cmpLen(const Query& x, const Query& y) { return x.R > y.R; } Query tmp[N]; //q有序数组合并 inline void cdq(const int L, const int R) { const int mid = L + R >> 1; if (L == R) return; cdq(L, mid), cdq(mid + 1, R); int l = L, r = L - 1; //双指针找[q-K,q+K]范围内的所有圆心,加入树状数组 forn(curr, mid+1, R) { const auto& [pos,R,queryL,queryR,q] = node[curr]; while (l <= mid and q - K > node[l].q) add(node[l++].pos, -1); while (r < mid and node[r + 1].q <= q + K) add(node[++r].pos, 1); ans += queryLR(queryL, queryR); } forn(i, l, r) add(node[i].pos, -1); merge(node + L, node + mid + 1, node + mid + 1, node + R + 1, tmp + L); //使q有序 forn(i, L, R) node[i] = tmp[i]; } inline void solve() { Rd(n, K); forn(i, 1, n) { auto& [pos,R,_1,_2,q] = node[i]; Rd(pos, R, q); t[++tot] = pos, t[++tot] = pos + R, t[++tot] = pos - R; } sortArr(t, tot), tot = disc(t, tot); forn(i, 1, tot) mp[t[i]] = i; //离散化 forn(i, 1, n) { auto& [pos,R,l,r,q] = node[i]; l = mp[node[i].pos - node[i].R]; r = mp[node[i].pos + node[i].R]; pos = mp[node[i].pos]; } stable_sort(node + 1, node + n + 1, cmpLen); cdq(1, n); cout << ans; } signed int main() { Spider //------------------------------------------------------ int test = 1; // read(test); // cin >> test; forn(i, 1, test) solve(); // while (cin >> n, n)solve(); // while (cin >> test)solve(); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统