首页 > 其他分享 >选数 题解

选数 题解

时间:2023-01-11 08:22:58浏览次数:41  
标签:pre 选数 int 题解 ans oplus now

选数 题解

首先,设最初取值为\(x\),按照套路,我们设异或前缀和:\(pre_i=a_1\oplus a_2…\oplus a_i\),设\(f(x)=\left(\left\lfloor\frac{2x}{2^n}\right\rfloor+2x\right)\bmod 2^n\)

注意到:\(0\le a_i<2^n\),也即其二进制下不会超过\(n\)位。

那么我们实际上要求的即为:\(\max_{i=0}^m f(x\oplus pre_i)\oplus pre_n\oplus pre_i\)

简单带入一下\(f\),容易得到:

\(f(x\oplus pre_i)=f(x)\oplus f(pre_i)\)

有趣的是,\(f(x)\)相当于是将\(x\)在二进制下向左做一个一个单位长度的循环

这也可以证明我们对下列所有的\(f\)的变换是正确的,每一个\(f(x)\)都有唯一的值与之对应。

所以式子变为:\(f(x)\oplus f(pre_i)\oplus pre_n\oplus pre_i\),其中后半截的可以预处理的,不妨设\(s_i=f(pre_i)\oplus pre_n\oplus pre_i\)

将\(s_1\sim s_n\)插入trie,并且注意到可以在不异或任何值的情况下对\(x\)进行变化,所以需要插入0别问90pts是为什么

再者,再看这个式子:\(\max_{i=0}^m f(x)\oplus s_i\),注意到\(x\in [0,2^n-1],f(x)\in[0,2^n-1]\),所以可以将\(f(x)\)用\(x\)替换掉。

这样的话,式子化为\(\max_{i=0}^m x\oplus s_i\),我们的问题就变成了如何求得这个最大值。

我们设solve(p,now,ans)表示当前遍历到trie的指针\(p\),已经计算到第\(now\)位,答案最大为\(ans\)

此时我们来分类讨论,毕竟先后手都足够聪明。

  1. 若\(p\)有两个儿子,则不论第\(now\)位填什么,都有决策使这个位变为0,所以递归solve(t[p][0],now-1,ans<<1),slove(t[p][1],now-1,ans<<1)
  2. 若\(p\)仅有一个儿子,则可以反着填数,使这一位变成1。设儿子为\(k\),则递归solve(k,now-1,ans<<1|1)
  3. 若\(p\)没有儿子,直接返回(ans,1)(最大值和个数)

最后返回值是返回各个分支的最大值,注意个数的统计。

核心代码如下:

#define pr pair<int,int>
#define mk make_pair
pr query(int p,int ans){
	if(t[p][0]==0&&t[p][1]==0)return mk(ans,1);
	if(t[p][0]&&t[p][1]){
		pr ans1=query(t[p][0],ans<<1);
		pr ans2=query(t[p][1],ans<<1);
		if(ans1.first==ans2.first)return mk(ans1.first,ans1.second+ans2.second);
		return max(ans1,ans2);
	}
	if(t[p][0])return query(t[p][0],ans<<1|1);
	return query(t[p][1],ans<<1|1);
}
signed main(){
	ios::sync_with_stdio(false);
	cin>>n>>m;
	n2=1;for(int i=1;i<=n;i++)n2*=2;
	for(int i=1;i<=m;i++)cin>>a[i];
	for(int i=1;i<=m;i++)pre[i]=pre[i-1]^a[i];
	for(int i=1;i<=m;i++)s[i]=get(pre[i])^pre[n]^pre[i];
	for(int i=1;i<=m;i++)insert(s[i]);
	insert(0);
	pr ans=query(1,0);
	cout<<ans.first<<endl<<ans.second<<endl;
}

标签:pre,选数,int,题解,ans,oplus,now
From: https://www.cnblogs.com/oierpyt/p/17042742.html

相关文章

  • Codeforces Round #843 (Div. 2) 题解
    A题目大意给你一个只含字母a,b字符串,要把它拆分成三段,使得其中间那段要么同时小于等于两边要么同时大于等于两边。题解由于只有a,b我们可以分讨解决如果\([2,......
  • CF1783 A-F 题解
    比赛链接:https://codeforces.com/contest/1783连续三场出4题,还行(其实感觉有两场的E都是会做的)A水题//bySkyRainWind#include<bits/stdc++.h>#definemprmake_pai......
  • 「JOI Open 2022」Giraffes 题解
    设我们将要给出的观感好的排列为\(q\),我们希望求出\(\sum[p_i=q_i]\)的最大值(这里指不移动的长颈鹿个数)。结论一:当且仅当左右端点有当前区间最大值或者最小值时条件才......
  • 题解1
    离散化1.为什么要离散化当数据很大的时候,以至于我们不能直接使用它的时候,就要考虑将其用另外一种形式表达,通常是将其映射为数组下标。2.离散化本质本质:映射3.离......
  • charls抓包的乱码问题解决
    1.在charls的安装目录下,去修改配置文件的值----Charles.ini,内容如下   2.SSLproxysetting设置如下图  3.顺便说一下,charls抓取https的包,一定要先安......
  • docker中crontab无法执行导入计划任务问题解决
    问题描述:crontab无法执行导入计划任务解决: ⊙查看文件16进制 hexdump-c./crontab/defalut   发现有\r;crontab中只能直接\n⊙vim文件修改编码   setfile......
  • P3521 题解
    非线段树合并做法。复杂度多一只log,但是好写。跳过不重要的部分,直达核心——如何在递归时计算两棵子树互相的贡献?题解区清一色线段树合并从值域角度考虑。但是显然倍......
  • [IOI2000]邮局 题解
    简要题意线段上有\(V\)个村庄,现在要建\(P\)个邮局,使每个村庄到最近的邮局的距离之和最小。50分做法设\(dp[i][j]\)表示第一个村庄到第\(i\)个村庄,建了\(j\)个......
  • mysql delete大量数据表锁死,kill的线程后线程处于killed状态问题解决
    一、事件起因删除一张500G的表,没有添加任何约束条件,结果好久都没反应,查询锁之后,使用kill杀掉了进程,再次查询的时候,锁还在,trx_state的状态是ROLLINGBACK,使用showprocessl......
  • 网络流二十四题解题报告
    网络流二十四题解题报告\(\text{ByDaiRuiChen007}\)来源:LOJ-网络流24题机器人路径规划问题数据有误,不计入解题报告中1.飞行员配对方案问题ProblemLink构造二......