zoukankan      html  css  js  c++  java
  • BZOJ4571: [Scoi2016]美味

    BZOJ4571: [Scoi2016]美味

    Description

    一家餐厅有 n 道菜,编号 1...n ,大家对第 i 道菜的评价值为 ai(1≤i≤n)。
    有 m 位顾客,第 i 位顾客的期望值为 bi,而他的偏好值为 xi 。
    因此,第 i 位顾客认为第 j 道菜的美味度为 bi XOR (aj+xi),XOR 表示异或运算。
    第 i 位顾客希望从这些菜中挑出他认为最美味的菜,即美味值最大的菜,但由于价格等因素,他只能从第 li 道到第 ri 道中选择。
    请你帮助他们找出最美味的菜。

    Input

    第1行,两个整数,n,m,表示菜品数和顾客数。
    第2行,n个整数,a1,a2,...,an,表示每道菜的评价值。
    第3至m+2行,每行4个整数,b,x,l,r,表示该位顾客的期望值,偏好值,和可以选择菜品区间。
    1≤n≤2×10^5,0≤ai,bi,xi<10^5,1≤li≤ri≤n(1≤i≤m);1≤m≤10^5

    Output

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

    Sample Input

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

    Sample Output

    9
    7
    6
    7

    题解Here!

    看到异或,就应该想到要用可持久化$Trie$树来搞搞事。
    对于这道题,我们需要借鉴一下最大异或和的解题思想。
    于是省去了建$Trie$树的部分。
    我们想,可持久化$Trie$树的核心思想是贪心,一位一位贪心。
    所以我们同样是按照数位一位一位的贪心。
    因为加了一个$x$,所以我们考虑对于所有的$a_i+x$与$b$的按位异或。
    假设我们已经处理到$b$的二进制第$i$位,假设是这一位上是$1$。
    那么我们只需要查找是否存在$a_j+x$使得其二进制第$i$位数字是$0$即可。
    由于我们已经处理了前$i-1$位了,那么设前$i-1$位结果是$ans$。
    于是我们需要查找的数的大小就是在区间$[ans-x,ans+(1<<i)-1-x]$中。
    手算一下就知道这个区间里的数字的第$i$位加了$x$后就都是$0$。
    对于$0$同理。
    那么现在我们就是要在$a_1,a_2,...,a_n$中找出是否存在于$[ans-x,ans+(1<<i)-1-x]$的数字。
    这个区间范围限制,我们直接线段树就好了。
    那,那个外层区间范围限制怎么整?
    我们不是根据前一位推出了当前这一位嘛。。。
    那就用个主席树来维护一下嘛。。。
    主席树直接上板子。。。
    然后就完结了。。。
    附代码:
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #define MAXN 200010
    using namespace std;
    int n,m,K,size=0;
    int val[MAXN],root[MAXN];
    struct Chairman_Tree{
    	int sum,l,r;
    }a[MAXN*20];
    inline int read(){
    	int date=0,w=1;char c=0;
    	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    	return date*w;
    }
    inline void buildtree(){
    	root[0]=a[0].l=a[0].r=a[0].sum=0;
    }
    void insert(int k,int l,int r,int &rt){
    	a[++size]=a[rt];rt=size;
    	a[rt].sum++;
    	if(l==r)return;
    	int mid=l+r>>1;
    	if(k<=mid)insert(k,l,mid,a[rt].l);
    	else insert(k,mid+1,r,a[rt].r);
    }
    int query(int l,int r,int lside,int rside,int i,int j){
    	if(l<=lside&&rside<=r)return a[j].sum-a[i].sum;
    	int mid=lside+rside>>1,ans=0;
    	if(l<=mid)ans+=query(l,r,lside,mid,a[i].l,a[j].l);
    	if(mid<r)ans+=query(l,r,mid+1,rside,a[i].r,a[j].r);
    	return ans;
    }
    bool check(int l,int r,int x,int y){
    	x=max(0,x);y=min(y,K);
    	if(x>y)return 0;
    	return query(x,y,0,K,root[l],root[r]);
    }
    inline int solve(int b,int x,int l,int r){
    	int ans=0,now;
    	for(int i=17;i>=0;i--){
    		now=ans+((1^((b>>i)&1))<<i);
    		if(check(l-1,r,now-x,now+(1<<i)-x-1))ans=now;
    		else ans+=((b>>i)&1)<<i;
    	}
    	return (ans^b);
    }
    void work(){
    	int l,r,x,b;
    	while(m--){
    		b=read();x=read();l=read();r=read();
    		printf("%d
    ",solve(b,x,l,r));
    	}
    }
    void init(){
    	n=read();m=read();
    	K=((MAXN-10)>>1);
    	for(int i=1;i<=n;i++)val[i]=read();
    	buildtree();
    	for(int i=1;i<=n;i++){
    		root[i]=root[i-1];
    		insert(val[i],0,K,root[i]);
    	}
    }
    int main(){
    	init();
    	work();
        return 0;
    }
    
  • 相关阅读:
    近一年工作感悟2
    项目管理实践感想
    领导力思考
    ASP.NET内置对象
    asp.net 在GridView控件上实现修改、添加、删除
    asp.net导出excel和打印指定内容的简单代码
    js让网页适应屏幕大小
    只能选择GridView中的一个CheckBox(单选CheckBox)
    JQuery实现拖拽draggable()方法
    获取XML文件中的值
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9683222.html
Copyright © 2011-2022 走看看