CF1863F Divide, XOR, and Conquer 题解

简要题意

你有两个指针 \(l,r\) 初始时 \(l=1,r=n\)

你可以操作若干次知道 \(l=r\)

每次操作你可以选择一个整数 \(k \in [l,r)\),记 \(x=\bigoplus_{i=l}^k a_i,y=\bigoplus_{i=k+1}^r a_i\)

  • 如果 \(x \leq y\),你可以令 \(l=k+1\)
  • 如果 \(x \geq y\),你可以令 \(r=k\)

现在你需要对于每一个整数 \(i \in [1,n]\),求最后能否使 \(l=r=i\)

\(n \leq 10000\)\(0 \leq a_i < 2^{60}\)

做法

我们设 \(f_{x,y}\) 表示是否可以令 \(l=x,r=y\)

首先我们考虑一个区间 \([x,y]\) 可以到达,那么什么样的区间可以被它转移到。

\(q=\bigoplus_{i=l}^r a_i\)

  1. 如果 \(q=0\),那么区间 \([x,y]\) 可以转移到 \([x,x],[x,x+1]\dots [x,y-1]\)\([x+1,y],[x+2,y]\dots [y,y]\)
  2. 如果 \(q \neq 0\),我们设 \(h=\operatorname{highbit}(q)\)
    • 考虑左端点右移转移到 \([t,y]\),那么必然有 \(\bigoplus_{i=t}^y a_i \operatorname{and} h \neq 0\)
    • 考虑右端点左移转移到 \([x,t]\),那么必然有 \(\bigoplus_{i=x}^t a_i \operatorname{and}h \neq 0\)

考虑按照区间长度从大到小枚举 \(x,y\),然后看 \(f_{x,y}\) 是否可以被转移到。

首先一个区间 \([l,r]\) 能转移到 \([x,y]\) 首先要有 \(l=x\) 或者 \(r=y\)

然后就是 \(\operatorname{highbit}(\bigoplus_{i=l}^r a_i) \operatorname{and} (\bigoplus_{i=x}^ya_i) \neq 0\)

我们记录两个辅助转移的数组 \(L,R\),分别表示用来转移 \(l=x\)\(r=y\) 的情况。

看一个区间 \([x,y]\) 是否可以被转移到只需要看 \(\operatorname{highbit}(\bigoplus_{i=l}^r a_i) \operatorname{and} L_x \neq 0\)\(\operatorname{highbit}(\bigoplus_{i=l}^r a_i) \operatorname{and} R_y \neq 0\) 就行,两者满足其一即可转移。

如果求出了一个区间 \([x,y]\) 可以到达,那么我们只需要令 \(L_x=L_x \operatorname{or} \operatorname{highbit}(\bigoplus_{i=l}^r a_i)\)\(R_y=R_y \operatorname{or} \operatorname{highbit}(\bigoplus_{i=l}^r a_i)\) 即可。

放个代码可能好理解一些。

#include<bits/stdc++.h>

#define ll long long

using namespace std;

const int MAXN = 1e5+5;
const int mod = 200003;

int n;
int c[MAXN], tot;

ll stateL[MAXN], stateR[MAXN];

bool dp[10002][10002];

ll a[MAXN], pre[MAXN];

inline ll rebuild(ll x){
	tot=0;
	while(x){
		c[++tot]=x&1;
		x>>=1;
	}
	while(tot<=60) c[++tot]=0;
	reverse(c+1,c+1+tot); x=0;
	for(int i=1;i<=tot;++i) x+=(ll)c[i]<<(i-1);
	return x;
}

inline ll lowbit(ll x){return x & -x;}

inline void solve(){	
	cin >> n; ll v;
	for(int i=1;i<=n;++i) stateL[i]=stateR[i]=0;
	for(int i=1;i<=n;++i) cin >> a[i], a[i]=rebuild(a[i]), pre[i]=pre[i-1]^a[i];
	for(int i=1;i<=n;++i) for(int j=i;j<=n;++j) dp[i][j]=0; dp[1][n]=1;
	for(int len=n;len>=1;--len){
		for(int l=1, r=l+len-1;r<=n;++l, ++r){
			v=pre[r]^pre[l-1]; v|=1ll<<61;
			dp[l][r]|=((stateL[l]&v)!=0);
			dp[l][r]|=((stateR[r]&v)!=0);
			if(dp[l][r]) stateL[l]|=lowbit(v), stateR[r]|=lowbit(v);
		}
	}	
	for(int i=1;i<=n;++i) putchar('0'+dp[i][i]); putchar(10);
	return ;
}

int main(){
	int t; cin >> t;
	while(t--) solve();
	return 0;
}
posted @ 2024-02-08 19:58  OccDreamer  阅读(24)  评论(0)    收藏  举报