• [洛谷P3293] [SCOI2016]美味


    洛谷题目链接:[SCOI2016]美味

    题目描述

    一家餐厅有 n 道菜,编号 1...n ,大家对第 i 道菜的评价值为 ai(1<=i<=n)。有 m 位顾客,第 i 位顾客的期望值为 bi,而他的偏好值为 xi 。因此,第 i 位顾客认为第 j 道菜的美味度为 bi XOR (aj+xi),XOR 表示异或运算。

    第 i 位顾客希望从这些菜中挑出他认为最美味的菜,即美味值最大的菜,但由于价格等因素,他只能从第 li 道到第 ri 道中选择。请你帮助他们找出最美味的菜。

    输入输出格式

    输入格式:

    第1行,两个整数,n,m,表示菜品数和顾客数。

    第2行,n个整数,a1,a2,...,an,表示每道菜的评价值。

    第3至m+2行,每行4个整数,b,x,l,r,表示该位顾客的期望值,偏好值,和可以选择菜品区间。

    输出格式:

    输出 m 行,每行 1 个整数,ymax ,表示该位顾客选择的最美味的菜的美味值。

    输入输出样例

    输入样例#1:

    4 4
    1 2 3 4
    1 4 1 4
    2 3 2 3
    3 2 3 3
    4 1 2 4

    输出样例#1:

    9
    7
    6
    7

    说明

    对于所有测试数据,(1<=n<=2*10^ 5,0<=ai,bi,xi<10 ^ 5,1<=li<=ri<=n(1<=i<=m),1<=m<=10^5)

    题解: 如果没有这个(+x)的操作,就可以直接用(trie)查询最大异或值了,那么有这个(+x)的操作要怎么办呢?

    我们还是一样的建出(trie)树,然后以二进制枚举每一位的值.

    假设现在正在枚举第(i)位的答案((iin {0, 1, 2, ...})),填满第(i)位之前的结果为(ans),那么以贪心的思想,这一位填入(((1 xor {((b>>i)&1))}<<i))一定是最优的,然后填完这一位之后后面还有(i)个位置可以填入(0)(1),那么这些数字任意填入后的取值范围就是([0,(1<<i)-1]),如果在(trie)树中可以找到存在值在([ans+((1 xor {((b>>i)&1))}<<i)-x,ans+((1 xor {((b>>i)&1))}<<i)-(1<<i)-1])范围内的,说明这一位可以贪心的选,否则只能在这一位填入((({((b>>i)&1))}<<i)).

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 2e5+5;
    
    int n, m, a[N], cnt = 0, root[N], ans = 0, mx;
    
    struct trie{ int ch[2], size; }t[N*20];
    
    void update(int &x, int last, int pos, int l = 0, int r = mx){
        x = ++cnt; t[x] = t[last], t[x].size++;
        if(l == r) return; int mid = (l+r>>1);
        if(pos <= mid) update(t[x].ch[0], t[last].ch[0], pos, l, mid);
        else update(t[x].ch[1], t[last].ch[1], pos, mid+1, r);
    }
    
    int query(int x, int last, int ql, int qr, int l = 0, int r = mx){
        if(ql <= l && r <= qr) return t[x].size-t[last].size;
        int mid = (l+r>>1), sum = 0;
        if(t[x].ch[0] && ql <= mid) sum += query(t[x].ch[0], t[last].ch[0], ql, qr, l, mid);
        if(t[x].ch[1] && mid < qr) sum += query(t[x].ch[1], t[last].ch[1], ql, qr, mid+1, r);
        return sum;
    }
    
    int check(int x, int y, int l, int r){
        l = max(0, l), r = min(r, mx); if(l > r) return 0;
        return query(root[y], root[x], l, r);
    }
    
    int main(){
        int b, x, l, r; cin >> n >> m;
        for(int i = 1; i <= n; i++) cin >> a[i], mx = max(mx, a[i]);
        for(int i = 1; i <= n; i++) update(root[i], root[i-1], a[i]);
        for(int i = 1; i <= m; i++){
            cin >> b >> x >> l >> r, ans = 0;
            for(int j = 19; j >= 0; j--){
                int tmp = ans+((((b >> j) & 1) ^ 1) << j);
                if(check(l-1, r, tmp-x, tmp+(1 << j)-1-x)) ans = tmp;
                else ans += (((b >> j) & 1) << j);
            }
            cout << (ans^b) << endl;
        }
        return 0;
    }
    
  • 相关阅读:
    使用def文件简化dll导出
    ASP.NET Core MVC 之过滤器(Filter)
    ASP.NET Core 中间件 中间件(Middleware)和过滤器(Filter)的区别
    drf-apiview解读系列二
    干货分享,40个photoshop技能送给你!
    冒泡排序 深度优化
    数据结构与算法_14 _ 排序优化:如何实现一个通用的、高性能的排序函数
    数据结构与算法_12 _ 排序(下):如何用快排思想在O(n)内查找第K大元素
    数据结构与算法_13 _ 线性排序:如何根据年龄给100万用户数据排序
    数据结构与算法_11 _ 排序(上):为什么插入排序比冒泡排序更受欢迎
  • 原文地址:https://www.cnblogs.com/BCOI/p/10444696.html
Copyright © 2020-2023  润新知