洛谷 P3293 [SCOI2016] 美味
题目描述
一家餐厅有 n 道菜,编号 1,2,…,n,大家对第 i 道菜的评价值为 ai。有 m 位顾客,第 i 位顾客的期望值为 bi,而他的偏好值为 xi。因此,第 i 位顾客认为第 j 道菜的美味度为 bi⊕(aj+xi),⊕ 表示异或运算。
第 i 位顾客希望从这些菜中挑出他认为最美味的菜,即美味值最大的菜,但由于价格等因素,他只能从第 li 道到第 ri 道中选择。请你帮助他们找出最美味的菜。
对于 100% 的数据,满足 1≤n≤2×105,0≤ai,bi,xi<105,1≤li≤ri≤n(1≤i≤m),1≤m≤105。
解析
看到异或就考虑按位贪心一下。
从高位按二进制开始枚举,记录一个满足题目限制的 ans=a+x.
设当前枚举到第 i 位,b 在这一位上的值为 b′i.
分类讨论:
-
若 b′i=1,要使答案最大即是让 (a+x) 的这一位为 0,容易发现当且仅当新的答案在 [ans,ans+2i−1] 中,即 a∈[ans−x,ans+2i−1−x].
-
若 b′i=0,就要尽可能满足 (a+x) 的这一位为 1,当且仅当新的答案在 [ans+2i,ans+2i+1−1] 中, a∈[ans+2i−x,ans+2i+1−1−x].
只需要查找是否存在值在以上区间内的 a 即可。如果存在就取最优的答案,否则这一位只能取另外的值。
在某个区间 [l,r] 内查找值域在某个区间 [L,R] 中的数,就是经典的可持久化线段树板子了(虽然也能用树套树做)。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int n, m, a[N], b, x, l, r, idx, lc[N << 5], rc[N << 5], val[N << 5], root[N];
void pushup(int x)
{
val[x] = val[lc[x]] + val[rc[x]];
}
int build(int x, int l, int r)
{
if(!x) x = ++idx;
if(l == r) return x;
int mid = (l + r) >> 1;
lc[x] = build(lc[x], l, mid);
rc[x] = build(rc[x], mid + 1, r);
return x;
}
int update(int x, int y, int p, int l, int r)
{
if(y == x || !y)
{
y = ++idx;
lc[y] = lc[x];
rc[y] = rc[x];
val[y] = val[x];
}
if(l == r && l == p)
{
val[y]++;
return y;
}
int mid = (l + r) >> 1;
if(p <= mid) lc[y] = update(lc[x], lc[y], p, l, mid);
if(mid < p) rc[y] = update(rc[x], rc[y], p, mid + 1, r);
pushup(y);
return y;
}
int query(int x, int y, int L, int R, int l, int r) // 查询版本 [x+1, y] 中的区间 [L, R]
{
if(l > r) return 0;
if(L <= l && r <= R) return val[y] - val[x];
int mid = (l + r) >> 1, res = 0;
if(L <= mid) res += query(lc[x], lc[y], L, R, l, mid);
if(mid < R) res += query(rc[x], rc[y], L, R, mid + 1, r);
return res;
}
int main()
{
ios :: sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> m;
root[0] = build(root[0], 0, 1e5);
for(int i = 1; i <= n; i++)
cin >> a[i], root[i] = update(root[i - 1], root[i], a[i], 0, 1e5);
for(int i = 1; i <= m; i++)
{
cin >> b >> x >> l >> r;
int ans = 0;
for(int j = 20; j >= 0; j--)
{
int o = b & (1 << j);
if(!o) ans += (1 << j) * (bool) query(root[l - 1], root[r], ans + (1 << j) - x, ans + (1 << (j + 1)) - x - 1, 0, 1e5);
else ans += (1 << j) * !(bool) query(root[l - 1], root[r], ans - x, ans + (1 << j) - x - 1, 0, 1e5);
}
cout << (ans ^ b) << '\n';
}
return 0;
}
望穿寂夜晨曦至,雄鹰展翅图九天。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】