• BZOJ4571: [Scoi2016]美味


    BZOJ4571: [Scoi2016]美味

    https://lydsy.com/JudgeOnline/problem.php?id=4571

    分析:

    • 比较好的一道题。
    • 按位贪心,假设由已经确定的那些位组成的数为(ans)
    • (c)((ans+(1<<i));xor;b) 低于(i)的位都是(0)的结果。
    • 那么合法的数的区间就是([c-x,c+(1<<i)-1-x])
    • 每次主席树查区间是否存在一个数即可。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cstdlib>
    using namespace std;
    #define N 200050
    #define inf 100000
    int n,a[N],m,root[N],cnt;
    int ls[N*22],rs[N*22],siz[N*22];
    void update(int l,int r,int x,int &p,int q) {
    	p=++cnt; ls[p]=ls[q]; rs[p]=rs[q]; siz[p]=siz[q]+1;
    	if(l==r) return ;
    	int mid=(l+r)>>1;
    	if(x<=mid) update(l,mid,x,ls[p],ls[q]);
    	else update(mid+1,r,x,rs[p],rs[q]);
    }
    int query(int l,int r,int x,int y,int p,int q) {
    	if(siz[p]==siz[q]) return 0;
    	if(x<=l&&y>=r) return siz[p]-siz[q];
    	int mid=(l+r)>>1,re=0;
    	if(x<=mid) re+=query(l,mid,x,y,ls[p],ls[q]);
    	if(y>mid) re+=query(mid+1,r,x,y,rs[p],rs[q]);
    	return re;
    }
    int mask=(1<<18)-1;
    int qian(int p,int d) {
    	return d&(mask-((1<<p)-1));
    }
    int main() {
    	scanf("%d%d",&n,&m);
    	int i;
    	for(i=1;i<=n;i++) scanf("%d",&a[i]),update(0,inf,a[i],root[i],root[i-1]);
    	int ans;
    	while(m--) {
    		int b,x,l,r;
    		scanf("%d%d%d%d",&b,&x,&l,&r);
    		ans=0;
    		for(i=17;i>=0;i--) {
    			int t=ans+(1<<i);
    			int c=qian(i,t^b);
    			int mn=max(c-x,0),mx=min(c+(1<<i)-1-x,inf);
    			if(mn<=mx&&query(0,inf,mn,mx,root[r],root[l-1])) {
    				ans+=(1<<i);
    			}
    		}
    		printf("%d
    ",ans);
    	}
    }
    
    
  • 相关阅读:
    GRUB引导——menu.lst的写法
    条形码类型及常见条形码介绍
    Tmux:终端复用器
    find+*的问题
    find命令之exec
    Linux core 文件介绍
    C语言中返回字符串函数的四种实现方法
    C语言中的volatile
    Stars
    Game with Pearls
  • 原文地址:https://www.cnblogs.com/suika/p/10093081.html
Copyright © 2020-2023  润新知