cf1415D. XOR-gun(思维)

发布时间 2023-11-09 18:27:42作者: gan_coder

https://codeforces.com/problemset/problem/1415/D

从高位到低位考虑,需要注意的是我们的最后一个数可能是有后面的数异或来的,需要记录异或了几次(下面会说)
如果当前这一位全都为0,直接下一位
如果当前这一位出现了至少4个1,那么答案为1。
如果只有一个1,那么显然应该直接把这个1丢掉,因为这个这个高位的1没办法去掉,所以无论如何都不会比前面的小
如果有3个1,我们可以分成两种情况,是否使用最后一个,假如使用最后一个,那么答案应该是,c[r]+1,c[r]表示最后一个是由多少个数异或来的
否则转化为2个1的情况
如果有2个1,那么简单枚举一下分割点在 r-1之前,还是r之前,然后分类一下就行。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
#include<vector>
#include<set>
#include<queue>
#define A puts("YES")
#define B puts("NO")
#define fo(i,a,b) for (int (i)=(a);(i)<=(b);(i)++)
#define fd(i,b,a) for (int (i)=(b);(i)>=(a);(i)--)
#define mk(x,y) make_pair((x),(y))
#define lc (o<<1)
#define rc (o<<1|1)
using namespace std;
//typedef __int128 i128;
typedef double db;
typedef long long ll;
const ll mo=1e9+7;
const int inf=1<<30;
const int N=1e5+5;
int n,a[N],b[50],ans,c[N];
void solve(int l,int r,int k){
	if (l+1>=r) return;
	int tot=0;

	fo(i,l,r) if (a[i]&b[k]) ++tot;
	
	if (!tot) {
		solve(l,r,k-1);
	}
	if (tot>3) {
		ans=1; return;
	}
	
	if (tot==1) {
		solve(l,r-1,k-1); return;
	}
	
	if (tot==3) {
		ans=min(ans, c[r-1]+c[r]+1);
		solve(l,r-1,k);
		return;
	}
	
	if (tot==2) {
		
		int x=a[r-1];
		fd(i,r-2,l) {
			x^=a[i];
			if (x>a[r]) {
				ans=min(ans, r-1-i+c[r]);
				break;
			}
		}
		
		x=0;
		fd(i,r-2,l) {
			x^=a[i];
			if (x>(a[r]^a[r-1])) {
				ans=min(ans, r-2-i+c[r]+c[r-1]+1);
				break;
			}
		}
	
		if (l+1==r) return;
		
		if ((a[r]^a[r-1])<a[r-2]) {
			solve(l,r-2,k-1);
		}
		else {
			c[r-1]+=c[r]+1;
			a[r-1]^=a[r];
			solve(l,r-1,k-1);
		}
	}
}
int main()
{
//	freopen("data.in","r",stdin);
//	freopen("ans.out","w",stdout);
	
	b[0]=1;
	fo(i,1,30) b[i]=b[i-1]*2;
	
	scanf("%d",&n);
	fo(i,1,n) scanf("%d",&a[i]);
	
	ans=inf;
	solve(1,n,30);
	
	if (ans==inf) puts("-1");
	else printf("%d",ans); 
	
	return 0;
}