1. 程式人生 > 實用技巧 >CodeForces E. XOR and Favorite Number(Div.2)

CodeForces E. XOR and Favorite Number(Div.2)

題目連結:E. XOR and Favorite Number

題解

一個莫隊的基礎題,題目要求[L,R]裡面有多少對子區間異或值為k,記錄一下字首異或和arr,因為x^x=0,現在我們要求區間[L,R]的異或和值,用arr陣列表示就是arr[L-1]^arr[R]=k,或者說arr[R]^k=arr[L-1]

import java.io.BufferedInputStream;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;

public class Main {
	
	final static int N = 1 << 21;
	static long nowAns = 0;//當前答案
	static int n,m,k,block;
	static long[] cnt = new long[N];//每個數出現的次數
	static long[] ans = new long[N];//記錄每個答案
	static int[] arr = new int[N];//字首異或和
	static Query[] q = new Query[N];//詢問
	
	public static class cmp implements Comparator<Query> {
		public int compare(Query x,Query y) {
			if(x.l / block == y.l / block)
				return x.r - y.r;
            return x.l / block - y.l / block;
		}
	}
		
	public static void remove(int x) {
		cnt[arr[x]]--;
		nowAns -= cnt[arr[x] ^ k];
	}

	public static void add(int x) {
		nowAns += cnt[arr[x] ^ k];
		cnt[arr[x]]++;
	}
	
	public static void main(String[] args) {
		Scanner cin = new Scanner(new BufferedInputStream(System.in));
		int l = 1,r = 0;
		n = cin.nextInt();//陣列長度
		m = cin.nextInt();//詢問次數
		k = cin.nextInt();
		block = (int) Math.sqrt(n);//每塊的大小
		for(int i = 1;i <= n;i++) {
			int tmp = cin.nextInt();
			arr[i] = arr[i - 1] ^ tmp;
		}
		for(int i = 1;i <= m;i++) {
			int tmp_l = cin.nextInt();
			int tmp_r = cin.nextInt();
			q[i] = new Query(tmp_l,tmp_r,i);//減1是為了將詢問轉換為下標
		}
		Arrays.sort(q,1,m + 1,new cmp());//sort是左閉右開的區間
		cnt[0] = 1;
		for(int i = 1;i <= m;i++) {
			while(l < q[i].l) {
				remove(l - 1);//移出數字
				l++;
			}
			while(l > q[i].l) {
				l--;
				add(l - 1);//加入數字
			}
			while(r < q[i].r) add(++r);//加入數字
			while(r > q[i].r) remove(r--);//移出數字
			ans[q[i].id] = nowAns;
		}
		for(int i = 1;i <= m;i++) System.out.println(ans[i]);
	}
}
class Query {
	int l,r,id;
	Query(int L,int R,int id) {
		this.l = L;
		this.r = R;
		this.id = id;
	}
}