ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P5283 [十二省联考 2019] 异或粽子

2022-02-02 22:31:17  阅读:135  来源: 互联网

标签:ch int ts long id 异或 num 2019 联考


给定 \(n\) 个整数 \(a_1,a_2...a_n\) ,求出所有子段异或和前 \(k\) 大的和 .

\(1\leq n\leq 5\cdot 10^5,0\leq k\leq \min(\frac{n(n-1)}{2},2\cdot 10^5),0\leq a_i\leq 2^{32}-1\)

前缀和数组为 \(b_0,b_1,b_2,\cdots b_n\) ,那么 \([l,r]\) 的字段异或和就是 \(b_r\oplus b_{l-1}\) . 就相当于两两的异或和 . 很像 \(\rm{cf241b\ friends}\) ,但是,那题 \(k\) 会达到 \(\frac{n(n-1)}{2}\) ,但是此题只会有 \(2\cdot 10^5\) ,但是 \(n\) 的大小却是 \(10\) 倍 .

所以考虑枚举出来前 \(k\) 个最大的,而不是二分,考虑用一个 \(\rm{set}\) 维护对于每个 \(i\) 没有被枚举到的最大的异或和 . 然后每次找到最大的,加入答案,然后用 \(\rm{01trie}\) 找到当前 \(i\) 下一个插入 .

但是这样就会导致一个问题,\((i,j)\) 和 \((j,i)\) 会被计算两次 . 冷静一下发现,只要把 \(k\) 的数量乘上 \(2\) 倍,这个问题就可以解决 ,前 \(k\) 大的以 \((i,j)\) 和 \((j,i)\) 的形式每个都被计算到了两次 .

需要注意的是要开 \(\rm{long\ long}\) .

时间复杂度 : \(O(k\log a)\)

空间复杂度 : \(O(n\log a)\)

code

#include<bits/stdc++.h>
using namespace std;
char in[100005];
int iiter=0,llen=0;
inline char get(){
	if(iiter==llen)llen=fread(in,1,100000,stdin),iiter=0;
	if(llen==0)return EOF;
	return in[iiter++];
}
inline long long rd(){
	char ch=get();while(ch<'0'||ch>'9')ch=get();
	long long res=0;while(ch>='0'&&ch<='9')res=(res<<3)+(res<<1)+ch-'0',ch=get();
	return res;
}
inline void pr(long long res){
	if(res==0){putchar('0');return;}
	static int out[20];int len=0;
	while(res)out[len++]=res%10,res/=10;
	for(int i=len-1;i>=0;i--)putchar(out[i]+'0');
}
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
const int N=5e5+10;
int cnt=1;
class node{public:int num,ch[2];}ts[N*32];
inline void init(){for(int i=0;i<N*32;i++)ts[i]=(node){0,-1};}
inline void ins(long long val){
	int x=1;
	for(int i=31;i>=0;i--){
		int id=val>>i&1;
		if(!ts[x].ch[id])ts[x].ch[id]=++cnt;
		x=ts[x].ch[id];
	}
	ts[x].num++;
}
inline void dfs(int x){
	if(ts[x].ch[0]){
		dfs(ts[x].ch[0]);
		ts[x].num+=ts[ts[x].ch[0]].num;
	}
	if(ts[x].ch[1]){
		dfs(ts[x].ch[1]);
		ts[x].num+=ts[ts[x].ch[1]].num;
	}
}
inline long long qry(long long val,int k){
	long long res=0;
	int x=1;
	for(int i=31;i>=0;i--){
		int id=val>>i&1;
		if(!id){
			if(ts[x].ch[1]&&ts[ts[x].ch[1]].num>=k)x=ts[x].ch[1],res|=1ll<<i;
			else k-=ts[ts[x].ch[1]].num,x=ts[x].ch[0];
		}else{
			if(ts[x].ch[0]&&ts[ts[x].ch[0]].num>=k)x=ts[x].ch[0],res|=1ll<<i;
			else k-=ts[ts[x].ch[0]].num,x=ts[x].ch[1];
		}
	}
	return res;
}
int n,k;
int a[N],pos[N];
set<pair<long long,int> >s;
long long ans=0;
int main(){
	n=rd();k=rd();k=k<<1;n++;
	for(int i=1;i<n;i++)a[i]=rd();
	for(int i=1;i<n;i++)a[i]^=a[i-1];
	for(int i=0;i<n;i++)ins(a[i]);
	dfs(1);
	for(int i=0;i<n;i++)s.insert(mp(-qry(a[i],++pos[i]),i));
	for(int i=0;i<k;i++){
		auto it=s.begin();
		int id=it->se;
		ans+=-it->fi;
		s.erase(s.begin());
		if(pos[id]+1<n)s.insert(mp(-qry(a[id],++pos[id]),id));
	}
	pr(ans/2);
	return 0;
}

标签:ch,int,ts,long,id,异或,num,2019,联考
来源: https://www.cnblogs.com/suadwm/p/15860892.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有