文章目录
- CF 1918C XOR-distance
- CF 1918D Blocking Elements
- CF 1918E ace5 and Task Order
CF 1918C XOR-distance
题目链接
这题出思路还挺快的,就是考虑二进制每一位的贡献,可惜写了个假的贪心
正确贪心是,考虑两种情况,第一种情况是当处理结束时,a ^ x比b ^ x大,另一种情况是a ^ x比b ^ x小
当结束时前面比后面大,遍历每一位中 a是1 b是0 的位置就要尽可能让 a 变成 0 b变成 1,这样需要的代价是2的位数的次方,可以减少的差值是两倍的次方
当结束时前面比后面小,遍历每一位中 a是0 b是1 的位置就要尽可能让 a 变成 1 b变成 0,这样需要的代价是2的位数的次方,可以减少的差值是两倍的次方
有个需要注意的点是,要单独处理一下ab第一个不同的数,如果结束a大于b,那第一个不同的数一定要是a为1 b为0,如果不是就要调整成这样,调整不了就不考虑这种情况,a小于b也是类似的
下面是我很啰嗦的代码,可以把后面类似的两部分写成一个函数
#include <bits/stdc++.h>using namespace std;#define int long longtypedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;const int N = 1000010;int cf[63];void init()
{cf[0] = 1;for (int i = 1; i <= 61; i ++ ) cf[i] = 2 * cf[i - 1];
}void solve()
{int a, b, r;cin >> a >> b >> r;if (a < b) swap(a, b);int ans = a - b;int res = ans;vector<int> aa, bb;if (a == 0) aa.push_back(0);if (b == 0) bb.push_back(0);int at = a, bt = b;while (at){aa.push_back(at & 1);at >>= 1;}while (bt){bb.push_back(bt & 1);bt >>= 1;}while (bb.size() < aa.size()) bb.push_back(0);int i = bb.size() - 1;int tmp = r;bool flag = false;while (i >= 0){if (!flag && aa[i] != bb[i]){flag = true;if (aa[i] == 0){if (cf[i] > r) break;else{r -= cf[i];ans -= 2 * cf[i];res = min(res, abs(ans));i -- ;continue;}}i -- ;continue;}if (r < cf[i] || aa[i] == bb[i]){i -- ;continue;}if (!flag && aa[i] == 0 && cf[i] >= r) break;if (aa[i] == 1 && bb[i] == 0 && flag){r -= cf[i];ans -= cf[i] * 2;res = min(abs(ans), res);}i -- ;}r = tmp;i = bb.size() - 1;ans = b - a;flag = false;while (i >= 0){if (!flag && aa[i] != bb[i]){flag = true;if (aa[i] == 1){if (cf[i] > r) break;else{r -= cf[i];ans -= 2 * cf[i];res = min(res, abs(ans));i -- ;continue;}}i -- ;continue; }if (r < cf[i] || aa[i] == bb[i]){i -- ;continue;}if (!flag && aa[i] == 0 && cf[i] >= r) break;if (bb[i] == 1 && aa[i] == 0 && flag){r -= cf[i];ans -= cf[i] * 2;res = min(abs(ans), res);}i -- ;}cout << res << '\n';
}signed main()
{ios::sync_with_stdio(false);cin.tie(0), cout.tie(0);init();int t = 1;cin >> t;while (t -- ){solve();}
}
CF 1918D Blocking Elements
题目链接
这题只能想到二分了,后面的单调队列没用过(极大可能是用过没总结就忘记了)
二分最终答案,然后让区间和都满足条件去判断端点和是否满足条件
dp[i]
表示以i
为最后一个分割点,最小的端点和是多少
j
表示以i
为最后一个端点,它前面能取到的最大的端点序号值
用sum
记录当前区间和,每当区间和超过mid
了就把最前面一个值删掉,更新j
然后用单调队列维护以i
为最后一个端点能取到的端点中端点和最小的序号,所以转移方程为dp[i] = dp[q.front()] + a[i]
关于单调队列总结在这
#include <bits/stdc++.h>using namespace std;#define int long longtypedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;const int N = 1000010;void solve()
{int n;cin >> n;vector<int> a(n + 2);for (int i = 1; i <= n; i ++ ) cin >> a[i];auto check = [&](int mid){vector<int> dp(n + 2);deque<int> q;int sum = 0;int j = 0;q.push_front(0);for (int i = 1; i <= n + 1; i ++ ){while (sum > mid) sum -= a[ ++ j];while (q.size() && q.front() < j) q.pop_front();if (!q.size()) return false;dp[i] = dp[q.front()] + a[i];while (q.size() && dp[q.back()] > dp[i]) q.pop_back();q.push_back(i);sum += a[i];}return dp[n + 1] <= mid;};int l = 0, r = 1e15;while (l < r){int mid = l + r >> 1;if (check(mid)) r = mid;else l = mid + 1;}cout << r << '\n';
}signed main()
{ios::sync_with_stdio(false);cin.tie(0), cout.tie(0);int t = 1;cin >> t;while (t -- ){solve();}
}
CF 1918E ace5 and Task Order
题目链接
这题还是挺妙的
目标是给数组排序,还有个用于比较的元素 x,通过这个想到题目的交互可能是利用快排的思想,小于x的丢到左边,大于丢到右边,然后左右两边再递归排序
数据已经有序的时候快排会退化到 O ( n 2 ) O(n^2) O(n2),所以做之前先打乱顺序
#include <bits/stdc++.h>using namespace std;#define int long longvoid solve()
{mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());int n;cin >> n;vector<int> pos(n); // 存储值i的位置for (int i = 0; i < n; i ++ ) pos[i] = i;shuffle(pos.begin(), pos.end(), rnd);auto ask = [&](int x){cout << "? " << x + 1 << endl;char nn;cin >> nn;return nn;};function<void(int, int)> qsort = [&](int l, int r){if (l >= r) return;int mid = pos[l + r >> 1];while (ask(mid) != '=') ;vector<int> a, b, c; // = > <for (int i = l; i <= r; i ++ ){if (pos[i] == mid) a.push_back(pos[i]);else{char t = ask(pos[i]);ask(mid);if (t == '<') c.push_back(pos[i]);else b.push_back(pos[i]);}}copy(c.begin(), c.end(), pos.begin() + l);copy(b.begin(), b.end(), pos.begin() + c.size() + l + 1);pos[l + c.size()] = mid;qsort(l, l + c.size() - 1);qsort(l + c.size() + 1, r);};qsort(0, n - 1);vector<int> ans(n);for (int i = 0; i < n; i ++ ) ans[pos[i]] = i;cout << "!";for (int i = 0; i < n; i ++ ) cout << ' ' << ans[i] + 1;cout << endl;
}signed main()
{ios::sync_with_stdio(false);cin.tie(0), cout.tie(0);int t = 1;cin >> t;while (t -- ){solve();}
}