2023河南萌新联赛第(二)场:河南工业大学 B.C

赛时就做出了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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值