2020 wannafly camp day6 H 異或詢問 —— 異或 + 前綴

題目鏈接:點我啊╭(╯^╰)╮在這裏插入圖片描述

解題思路:

    如果只考慮i=1nf(i)\sum_{i=1}^n f(i),也就是一段連續的區間,預處理前綴即可
    而f(i xor x)\sum f(i\ xor\ x),加上了一個異或後,區間就不連續了
    根據異或性質,會分成最多 loglog 個連續區間
    從高位到低位考慮,如果 nn 的第 pospos 位爲 11,若不考慮 nn 的低位
    若 xx 的這一位爲 00 ,則異或後是一段連續的區間:0,2pos1(0, 2^{pos-1})
    若 xx 的這一位爲 11 ,區間加上這一位即可

    每一位考慮完之後,要加上這一位的影響,再去考慮低位
    最後要清空影響,其實最後的影響就是 n xor xn\ xor\ x

#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
using pii = pair <int,int>;
const ll mod = 998244353;
const int maxn = 1e5 + 5;
int n, q, a[maxn];
ll pre[maxn];
vector <int> v;

ll gao(ll x){
	if(x < a[1]) return 0;
	int pos = upper_bound(v.begin(), v.end(), x) - v.begin() - 1;
	ll ret = pre[pos];
	if(x == v[pos]) return ret;
	ll num = upper_bound(a+1, a+1+n, x) - a - 1;
	ret += 1ll * (x - v[pos]) * num % mod * num % mod;
	return ret % mod;
}

ll query(int l, int r){
	return (gao(r) - gao(l-1) + mod) % mod;
}

ll solve(int n, int x){
	if(n < 0) return 0;
	ll ret = 0; int cur = 0;
	for(int i=30; ~i; i--){
		int u = x >> i & 1;
		if(n >> i & 1){
			ret += query(cur|(u<<i), (cur|(u<<i)) + (1<<i)-1);
			cur |= ((u ^ 1) << i);
		} else cur |= (u << i);
	}
	ret = (ret + query(cur, cur)) % mod;
	return ret;
}

int main() {
	scanf("%d%d", &n, &q);
	for(int i=1; i<=n; i++) scanf("%d", a+i), v.push_back(a[i]);
	sort(a+1, a+1+n);
	sort(v.begin(), v.end());
	v.erase(unique(v.begin(), v.end()), v.end());
	ll cnt = v.size(), num, lnum;
	for(int i=0; i<cnt; i++){
		num = upper_bound(a+1, a+1+n, v[i]) - a - 1;
		if(i == 0) pre[i] = num * num % mod;
		else pre[i] = pre[i-1] + num * num % mod + \
					 (v[i] - v[i-1] - 1) * lnum % mod * lnum % mod;
		pre[i] %= mod;
		lnum = num;
	}
	while(q--){
		int l, r, x;
		scanf("%d%d%d", &l, &r, &x);
		ll ans = solve(r, x) - solve(l-1, x);
		printf("%lld\n", (ans + mod) % mod);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章