CF1863F Divide, XOR, and Conquer 题解
简要题意
你有两个指针 初始时 。
你可以操作若干次知道 。
每次操作你可以选择一个整数 ,记 。
- 如果 ,你可以令 。
- 如果 ,你可以令 。
现在你需要对于每一个整数 ,求最后能否使 。
,。
做法
我们设 表示是否可以令 。
首先我们考虑一个区间 可以到达,那么什么样的区间可以被它转移到。
设 。
- 如果 ,那么区间 可以转移到 和 。
- 如果 ,我们设 。
- 考虑左端点右移转移到 ,那么必然有 。
- 考虑右端点左移转移到 ,那么必然有 。
考虑按照区间长度从大到小枚举 ,然后看 是否可以被转移到。
首先一个区间 能转移到 首先要有 或者 。
然后就是 。
我们记录两个辅助转移的数组 ,分别表示用来转移 和 的情况。
看一个区间 是否可以被转移到只需要看 和 就行,两者满足其一即可转移。
如果求出了一个区间 可以到达,那么我们只需要令 , 即可。
放个代码可能好理解一些。
#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; }
本文作者:OI 生活
本文链接:https://www.cnblogs.com/OccasionalDreamer/p/18012085
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
标签:
动态规划
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步