P8773 [蓝桥杯 2022 省 A] 选数异或

题目描述

给定一个长度为 nn 的数列 A_{1}, A_{2}, \cdots, A_{n}A1​,A2​,⋯,An​ 和一个非负整数 xx, 给定 mm 次查询, 每次询问能否从某个区间 [l, r][l,r] 中选择两个数使得他们的异或等于 xx 。

输入格式

输入的第一行包含三个整数 n, m, xn,m,x 。

第二行包含 nn 个整数 A_{1}, A_{2}, \cdots, A_{n}A1​,A2​,⋯,An​。

接下来 mm 行,每行包含两个整数 l_{i}, r_{i}li​,ri​ 表示询问区间 \left[l_{i}, r_{i}\right][li​,ri​] 。

输出格式

对于每个询问, 如果该区间内存在两个数的异或为 xx 则输出 yes, 否则输出 no

输入输出样例

输入 #1复制

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

输出 #1复制

yes
no
yes
no

说明/提示

【样例说明】

显然整个数列中只有 2,3 的异或为 1 。

【评测用例规模与约定】

对于 20 \%20% 的评测用例, 1 \leq n, m \leq 1001≤n,m≤100;

对于 40 \%40% 的评测用例, 1 \leq n, m \leq 10001≤n,m≤1000;

对于所有评测用例, 1 \leq n, m \leq 10^5,0 \leq x<2^{20}, 1 \leq l_{i} \leq r_{i} \leq n1≤n,m≤105,0≤x<220,1≤li​≤ri​≤n , 0 \leq A_{i}<2^{20}0≤Ai​<220 。

蓝桥杯 2022 省赛 A 组 D 题。

x=1时,2 xor 3 =1, 6 xor 7 =1 数对为(2,3) (6,7)...依次类推

使用动态规划,dp[i]保存1~i的区间范围内数对的最大左下标。

Last[a]保存的是a的下标。

动态转移方程为dp[i]=max(dp[i-1],Last[a*x]);

当 l 小于dp[r](即在1~r的范围内,数对的最大左下标时,此时包含至少一个数对) 为yes,否则为no

package lan;
import java.util.*;
public class lan9 {
 public static void main(String []args)
 {
	 Scanner in=new Scanner(System.in);
	 int n,m;
	    int x;//A[]记录数列
	    int l,r;
	   //dp[i]保存区间在1~i中数对的最大左下界
	   int dp[];
	   int A[];
	   int check[];//1表示yes,0表示no
	   HashMap<Integer,Integer> Last=new HashMap<Integer,Integer>();
	    n=in.nextInt();
	    m=in.nextInt();
	    x=in.nextInt();
	    dp=new int[n+1];
	    A=new int[n+1];
	    check=new int[n+1];
	
	    dp[0]=0;
	    for(int i=1;i<=n;i++)
	    	{ 
	    	  A[i]=in.nextInt();
	    	  Last.put(A[i], i);//A[i]最后一次出现的下标
	    	 
	    	  if(Last.get(A[i]^x)==null) dp[i]=dp[i-1];
		      else	dp[i]=Math.max(dp[i-1], Last.get(A[i]^x));
	    	}
	   
	    for(int i=1;i<=m;i++)
	    {
	    	l=in.nextInt();
	    	r=in.nextInt();
	    	if(dp[r]>=l) check[i]=1;
	    	else check[i]=0;
	    }
	    
	    for(int i=1;i<=m;i++)
	    	if(check[i]==1)System.out.println("yes");
	    	else System.out.println("no");
	    
 }
}

更新题解:使用线段树的方法

线段树每个节点表示一个区间,以及带有该区间的一个特殊值;

同时每个树节点满足 tree(l,r)=tree(l,mid)+tree(mid+1,r)


import java.util.*;
public class pro11{
	static final int maxn=10000+20;
	static int Left[]=new int[maxn];
	static int num[]=new int[maxn];
	static int tree[]=new int[maxn];
	static int a[]=new int[maxn],pos[]=new int[maxn];
	static int n,m,x;
	public static void main(String args[])
	{
		Scanner in=new Scanner(System.in);
		n=in.nextInt();
		m=in.nextInt();
		x=in.nextInt();
		for(int i=1;i<=n;i++)
		{
			a[i]=in.nextInt();
			Left[i]=pos[a[i]^x];//满足异或的左边界限的位置
			pos[a[i]]=i;
		}
		
		build(1,1,n);
		while((m--)!=0)
		{
			int l,r;
			l=in.nextInt();
			r=in.nextInt();
			if(query(1,1,n,l,r)>=l)
				System.out.println("yes");
			else System.out.println("no");
		}
			
	}
	
	public static void build(int o,int l,int r)
	{
		if(l==r) {
			tree[o]=Left[l];//第o个树节点在区间(l,r)满足异或条件的最左边位置
			return;
		}
		int mid=(r+l)/2;
		build(o<<1,l,mid);//左子树
		build(o<<1|1,mid+1,r);
		tree[o]=Math.max(tree[o<<1], tree[o<<1|1]);
	}
	
	public static int query(int o,int l,int r,int left,int right)
	{
		if(l>=left&&r<=right) return tree[o];//返回满足区间(right,left)的树结点值,(right,left)包含区间(l,r)
		int mid=(l+r)/2;
		int ans=0;
		if(mid>=left) ans=Math.max(query(o<<1,l,mid,left,right),ans);
		if(right>mid) ans=Math.max(query(o<<1|1,mid+1,r,left,right), ans);
		return ans;
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值