CF八九月杂题选做
CF八九月杂题选做
1863F
有一个长为
的数组 。 在每次操作中,你可以把数组分成两段,留下一段,扔掉另一段,要求前者的异或和不小于后者的。重复操作,直到只剩下一个数为止。
对于每个
,问最后剩下来的可不可能是第 个数。 有
组数据。 , , , 。
容易想到一个暴力DP,也即设
对于
时间复杂度
如何优化? 发现
我们来发现一下性质。设
发现硬生生比较是不可取的,而注意到
引理:对于三个数
,若 ,设 为 。则若 ,则有 。当 时有 。 证明:当
时,显然 ,下面我们讨论 的情况。 根据异或运算的性质,显然有
的第 位是 则说明 其中之一为 ,而若为 则说明二者这一位相同,比较无意义。 那么最高位的
就是第一个二者不同的二进制位,而 的意义也就是如此,谁占有这个 位谁更大,故引理成立。
这样我们就发现,我们仅仅只需要比较这一位即可得到二者大小。
有什么用处呢?这是很妙的。我们成功将比较
也即若
那么这是是容易维护的,发现这个最高位不过 64 种可能性,完全可以用一个数进行压缩,也即我们维护
只要二者的按位与不为0,则必定可以转移。(当然需要特判一下是否出现了
左边也是同理的。
#define N 10550
#define int long long
bool f[N][N];
int s[N],h[N],g[N],mnl[N],mnr[N];
int get(int x){
int res=__builtin_clzll(x);
return 1ll<<(63-res);
}
signed main(){
ios::sync_with_stdio(false);
int T;cin>>T;
while(T--){
int n;cin>>n;
for(int i=1;i<=n;i++)cin>>s[i],s[i]^=s[i-1],h[i]=g[i]=mnl[i]=mnr[i]=0;
f[1][n]=1;h[1]|=get(s[n]),g[n]|=get(s[n]);
if(!s[n])mnl[1]=mnr[n]=1;
for(int len=n-1;len;--len){
for(int l=1,r=len;r<=n;l++,r++){
f[l][r]=0;int k=s[r]^s[l-1];
if(mnl[l]||(k&h[l]))f[l][r]=1;
if(mnr[r]||(k&g[r]))f[l][r]=1;
if(f[l][r])h[l]|=get(k),g[r]|=get(k),mnl[l]|=(k==0),mnr[r]|=(k==0);
}
}
for(int i=1;i<=n;i++)cout<<f[i][i];
cout<<"\n";
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!