专栏文章
CF2143F
CF2143F题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @minuwz5v
- 此快照首次捕获于
- 2025/12/02 08:45 3 个月前
- 此快照最后确认于
- 2025/12/02 08:45 3 个月前
询问中位置 能取到的数是 中选数异或能得到的数。显然我们可以对每个左端点求出合法的最大 。此时有一个暴力,从前往后,设位置 操作后变成 ,在 的线性基中找到能表出的第一个大于 的数。
考虑固定左端点后,右端点线性基的变化次数是 的,可以一次处理一整段。求线性基变化点可以倒着枚举 ,将 加入变化点,然后枚举变化点加入线性基,删除未变化的点。根据线性基的性质,不会有非变化点变为变化点。
枚举每一段,设上一个数是 ,在这一段的线性基里查能表出的 的数的个数。若小于这一段的长度,更新 并退出。否则在线性基里查一次第 大更新 。能表出的 的数的个数和第 大都容易从高往低贪心计算。具体方式是分类讨论一下,枚举组合出的值与这个数的 LCP,如果在某一位比较出来了,线性基中比这一位低的数可以随便选。。
CPP#include<bits/stdc++.h>
using namespace std;
int t,n,m,a[200005],r[200005];
template<typename T,int maxn>struct basis{
T b[maxn];
int cnt;
basis(){
memset(b,0,sizeof(b)),cnt=0;
}
bool insert(T k){
if(cnt==maxn)return 0;
for(int i=maxn-1;i>=0;i--){
if(k>>i&1){
if(!b[i])return b[i]=k,cnt++,1;
k^=b[i];
}
}
return 0;
}
T query(int k,T ans=0){
if(k>=1<<maxn)return 1<<cnt;
for(int i=maxn-1,now=0,num=cnt;i>=0;i--){
if(b[i])num--;
if(k>>i&1){
if(~now>>i&1){
ans+=1<<num;
if(b[i])now^=b[i];
else return ans;
}
else if(b[i])ans+=1<<num;
}
else{
if(now>>i&1){
if(b[i])now^=b[i];
else return ans;
}
}
}
return ans;
}
T kth(int k){
T now=0;
for(int i=maxn-1,num=cnt;i>=0;i--){
if(!b[i])continue;
num--;
if(k<=1<<num){
if(now>>i&1)now^=b[i];
}
else{
k-=1<<num;
if(~now>>i&1)now^=b[i];
}
}
return now;
}
};
int main(){
ios::sync_with_stdio(0),cin.tie(0),cin>>t;
while(t--){
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
vector<int>p(1,n+1);
for(int i=n;i>=1;i--){
vector<int>nxt(1,i);
basis<int,20>b;
b.insert(a[i]);
for(int j=0;j<p.size()-1;j++)if(b.insert(a[p[j]]))nxt.push_back(p[j]);
nxt.push_back(n+1),p=nxt,b=basis<int,20>(),b.insert(a[i]);
for(int j=1,v=0;j<p.size();j++){
int num=b.query(v);
if((1<<b.cnt)-num<p[j]-p[j-1]){
r[i]=p[j-1]+(1<<b.cnt)-num-1;
break;
}
else r[i]=p[j]-1,v=b.kth(num+p[j]-p[j-1])+1;
b.insert(a[p[j]]);
}
}
for(int i=1,x,y;i<=m;i++)cin>>x>>y,puts(r[x]>=y?"Yes":"No");
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...