[十二省联考 2019] 异或粽子 题解
只能说相当套路的一道题目。
对于区间异或和,我们不妨先做一遍区间前缀异或和,记作 ,表示 的异或和,那么区间 的异或和即可转化为 ,那么我们呢只需对 个数字进行考虑,⚠️注意还有 。
既然题目让我们求 个粽子的最大值,那么我们不妨先求出第一大,再求出第二大,以此类推最后求出第 大,然后将这些全部加起来即可。
总共有 个组合,所以我们绝对不可能将所有的组合进行异或,这时不妨考虑另外一个套路:先搞出一个或几个必须选的,然后用这几个推出其他。
但是我们发现这题还有一个隐藏条件,选出来的 和 必须满足 ,这就非常蛋疼,因为这不仅要求找出异或最大的,还要求满足位置上的一定需求。
所以我们不妨将 ,这样就可以放松这个条件,毕竟如果选了 就必然会同时选上 ,最后再将答案除以 即可。
现在来考虑如何求出必须选的,既然是异或和,那么肯定要用到 ,可以求出对于 找出最大的 的值,这里不在赘述。对于每个位置,我们找到与其异或最大的,塞进堆里即可。
再来考虑如何通过一个值推出其他。显然,我们可以再先办法对于 求出第 大的总异或和,这样如果从堆里拿出一个排名为 的数,我们在往堆里塞一个排名为 的数字即可。
代码:
const int N=5e5+10,M=2e7; int n,k; LL a[N],sum[N]; int tot=1,tr[M][2],siz[M]; struct node { LL val; int id,rk; node(LL a,int b,int c) { val=a; id=b; rk=c; } friend bool operator < (node x,node y) { return x.val<y.val; } }; priority_queue<node> q; void ins(LL x) { int nd=1; for(int i=32;i>=0;i--) { int p=((x&(1ll<<i))!=0); siz[nd]++; if(tr[nd][p]) nd=tr[nd][p]; else {tr[nd][p]=++tot; nd=tot;} } siz[nd]++; } LL find(LL x,int rk) { int nd=1; LL ans=0; for(int i=32;i>=0;i--) { int p=((x&(1ll<<i))!=0); if(!tr[nd][!p]) nd=tr[nd][p]; else if(rk<=siz[tr[nd][!p]]) {nd=tr[nd][!p]; ans|=(1ll<<i);} else {rk-=siz[tr[nd][!p]]; nd=tr[nd][p];} } return ans; } int main() { n=read(); k=read(); k<<=1; ins(0); for(int i=1;i<=n;i++) { a[i]=read(); sum[i]=(sum[i-1]^a[i]); ins(sum[i]); } for(int i=1;i<=n;i++) { q.push({find(sum[i],1),i,1}); } LL ans=0; q.push({find(sum[0],1),0,1}); while(k) { auto t=q.top(); q.pop(); ans=ans+t.val; q.push({find(sum[t.id],t.rk+1),t.id,t.rk+1}); k--; } cout<<(ans/2); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效