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;
}
标签:XOR,gun,tot,cf1415D,异或,ans,return,include,define
From: https://www.cnblogs.com/ganking/p/17822508.html