题意:从所有区间长度大于l小于r的区间段中,选择最大的k个区间异或合相加,输出答案
这道题与P2048 [NOI2010]超级钢琴的思想相似,如果没有做过可以先去尝试一下超级钢琴。
P2048 [NOI2010]超级钢琴: 传送门
题解:由于异或一个相同的数,异或值为0所以对于前缀和来说,sum[r]XORsum[l-1]其实就是r到(l-1)的异或合,所以对于求的第几大值我们可以固定左端点,通过最大异或合的思想去求范围内的第k大的异或合
AC代码:
#include<stdio.h>
#include<vector>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
#define ll long long
using namespace std;
const int maxn=5e5+5;
//const ll inf=9223372036854775800;
//const int inf=1e5+5;
inline ll read(){
ll x=0,w=1;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')w=0,ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
struct node{
ll su;
int k,p;
friend bool operator < (node a,node b){
return a.su<b.su;
}
};
priority_queue<node> q;
int ls[maxn*80],rs[maxn*80],num1[maxn*80],num0[maxn*80],ti[maxn],tot;
ll er[35],ans;
int ai[maxn][35];
//0在左子树,1在右子树
inline void add(int*now,int lst,int len,int k,ll sum){
while(len>=0){
*now=++tot;
ls[*now]=ls[lst];
rs[*now]=rs[lst];
num1[*now]=num1[lst];
num0[*now]=num0[lst];
ai[k][len]=(sum>>len)&1;
if(ai[k][len])
num1[*now]++,now=&rs[*now],lst=rs[lst],len--;
else
num0[*now]++,now=&ls[*now],lst=ls[lst],len--;
}
}
inline void query(int now,int lst,int len,int k,int k1){
//printf("%lld %d %d %d %d %d\n",ans,len,nu0,nu1,now,lst);
int nu0,nu1;
while(len>=0){
nu0=num0[now]-num0[lst];
nu1=num1[now]-num1[lst];
if(ai[k1][len]){
if(nu0>=k){
ans+=er[len];
now=ls[now];
lst=ls[lst];
len--;
}
else{
now=rs[now];
lst=rs[lst];
len--;
k-=nu0;
}
}
else{
if(nu1>=k){
ans+=er[len];
now=rs[now];
lst=rs[lst];
len--;
}
else{
now=ls[now];
lst=ls[lst];
len--;
k-=nu1;
}
}
}
}
int main( ){
er[0]=1;
for(int a=1;a<=34;a++)
er[a]=er[a-1]*2;
ll n=read(),k=read();
ll sum=0;
tot=ti[0]=ls[0]=rs[0]=num1[0]=num0[0]=0;
memset(ai[0],0,sizeof(ai[0]));
for(int a=1;a<=n;a++){
sum^=read();
add(&ti[a],ti[a-1],34,a,sum);
}
for(int a=1;a<=n;a++){
ans=0;
query(ti[n],ti[a-1],34,1,a-1);
node now={ans,1,a};
q.push(now);
}
ll ans1=0;
while(k){
node now=q.top();
q.pop();
ans1+=now.su;
k--;
if(n-now.p+1<=now.k)
continue;
ans=0;
query(ti[n],ti[now.p-1],34,now.k+1,now.p-1);
now.su=ans;
now.k++;
q.push(now);
}
printf("%lld\n",ans1);
}