赛时就做出了ADEIG。。qwq
B 异星突击
B. 异星突击 |
考点:01字典树 其中 0 节点不储存任何东西 粉色为节点,蓝色为节点编号,如图为插入两个数字后的一棵01字典树
如图的树,共32层 (int 二进制有32位)
在字典树中插入
void insert(int x, int num) { // num为1时表示插入 num 为-1时表示删除(这样可以少写以一个del函数)
int p = 0; // 根节点通常设置为 0
for (int i = 31; ~i; -- i) {
int t = x >> i & 1;
if (!tr[p][t]) tr[p][t] = ++idx ; // 新建节点
p = tr[p][t];
cnt[p] += num; // cnt[i] 统计 i 节点的数字数量
}
}
查询
int find(int x, int h) {
int p = 0, res = 0;
for (int i = 31; ~i; -- i) {
int t = x >> i & 1; // x 这一位的值
int th = h >> i & 1; // h 这一位的值
if (!th) {// 若h当前位为0,则选择异或后值为1的所有数都能使结果大于h
res += cnt[tr[p][t ^ 1]]; // 异或后值为1的所有数数量
p = tr[p][t]; // 继续查找当前位异或后为0的数
} else { // h当前位为1,想要异或后大于h只能选择查找当前值异或后值为1的数
p = tr[p][t ^ 1];
}
if (!p) return res;
}
return res;
}
完整代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define qwq ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
const int N = 1e6 + 10, INF = 0x3f3f3f3f;
int n, hp;
int tr[N][2], cnt[N * 32], idx;
// cnt[i] 统计 i 节点的数字数量
void insert(int x, int num) {
int p = 0; // 根节点通常设置为 0
for (int i = 31; ~i; -- i) {
int t = x >> i & 1;
if (!tr[p][t]) tr[p][t] = ++idx ;
p = tr[p][t];
cnt[p] += num;
}
}
int find(int x, int h) {
int p = 0, res = 0;
for (int i = 31; ~i; -- i) {
int t = x >> i & 1; // x 这一位的值
int th = h >> i & 1; // h 这一位的值
if (!th) {// 若h当前位为0,则选择异或后值为1的所有数都能使结果大于h
res += cnt[tr[p][t ^ 1]]; // 异或后值为1的所有数数量
p = tr[p][t]; // 继续查找当前位异或后为0的数
} else { // h当前位为1,想要异或后大于h只能选择查找当前值异或后值为1的数
p = tr[p][t ^ 1];
}
if (!p) return res;
}
return res;
}
void solve() {
int op, x, h;
cin >> op;
if (op == 0) {
cin >> x;
insert(x, 1);
} else if (op == 1) {
cin >> x;
insert(x, -1);
} else {
cin >> x >> h;
int res = find(x, h);
cout << res << "\n";
if (!res) --hp;
}
//cout << hp << "\n";
}
int main() {
qwq; int T = 1;
cin >> T >> hp;
while (T -- )
solve();
cout << hp;
return 0;
}
C 悲伤的RT
当前分组会影响下一步的分组,考虑用动态规划
状态转移方程 dp[i] = max ( dp[i - 1], dp[i - c] + min({a[i - c + 1], a[i - c + 2] .....a[ i ] } ) )
区间最小值可以用滑动窗口来实现, 多个区间,可以定义pair类型的deque 储存值和位置
deque<pii> dq; // 滑动窗口 找最小值
// <a[i], i>
for (int i = 1; i <= n; ++ i) {
f[i] = f[i - 1]; // 先继承上一状态
while (dq.size() && dq.back().x > a[i]) dq.pop_back();
dq.push_back({a[i], i});
if (i - dq.front().y + 1 > c && dq.front().x == a[i - c]) // 队头滑出了窗口
dq.pop_front();
if (i >= c) f[i] = max(f[i], f[i - c] + dq.front().x);
}
完整代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define qwq ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
typedef pair<int, int> pii;
#define x first
#define y second
const int INF = 0x3f3f3f3f, N = 1e6 + 10;
ll a[N], f[N];
void solve() {
int n, c, ans = 0;
cin >> n >> c;
for (int i = 1; i <= n; ++ i)
cin >> a[i];
// f[i] = max(f[i - 1], f[i - c] + min({a[i-c+1], a[i-c+2]...a[i]}))
deque<pii> dq; // 滑动窗口 找最小值
// <a[i], i>
for (int i = 1; i <= n; ++ i) {
f[i] = f[i - 1];
while (dq.size() && dq.back().x > a[i]) dq.pop_back();
dq.push_back({a[i], i});
if (i - dq.front().y + 1 > c && dq.front().x == a[i - c]) // 队头滑出了窗口
dq.pop_front();
if (i >= c) f[i] = max(f[i], f[i - c] + dq.front().x);
}
cout << f[n];
}
int main() {
qwq; int T = 1;
//cin >> T;
while (T -- )
solve();
return 0;
}