题解:P17110 「FAOI-R13」XOR and Less(贪心)
Little_Zyl · · 题解
思路
考虑一个已经确定答案的区间,若在区间末尾新增一个数,如何快速更新答案。设新增的数的上限为
- 若
s 的这一位为0 ,贪心地将s 的这一位也设为1 ; - 若
s 的这一位已经为1 ,则a 的这一位无法继续提升s ,但注意到新增数的取值范围是[0,a] ,此时我们可以选择让新增数在该位取0 ,并允许所有更低位的取值任意,于是可以直接将s 在该位之后的所有低位全部置为1 。
因此,朴素做法可以枚举左端点
观察发现,
现在的问题是如何快速跳过那些不会改变
利用这个性质,我们可以预处理数组
在内层循环时,只需额外维护当前
完整代码
赛时代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=5e5+5,mod=998244353;
void read(int&x){
int t=0;
char c=getchar();
while(!isdigit(c))c=getchar();
while(isdigit(c))t=(t<<3)+(t<<1)+c-48,c=getchar();
x=t;
}
int n,a[N],sum,nxt[N][32];
ll ans;
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
read(n);
for(int i=1;i<=n;i++)read(a[i]);
for(int i=0;i<=31;i++)nxt[n][i]=n+1;
for(int i=n-1;i>=1;i--){
if(!a[i+1]){
for(int j=0;j<=31;j++)nxt[i][j]=nxt[i+1][j];
continue;
}
int t=__lg(a[i+1]);
for(int j=0;j<=t;j++)nxt[i][j]=i+1;
for(int j=t+1;j<=31;j++)nxt[i][j]=nxt[i+1][j];
}
for(int i=1;i<=n;i++){
for(int j=i,sum=0,cnt=0;j<=n;j=nxt[j][cnt]){
int aa=a[j];
while(aa){
int t=(1<<__lg(aa));
if((sum|t)==sum){sum|=t-1;break;}
sum|=t,aa^=t;
}
for(;sum&(1<<cnt);cnt++);
ans=(ans+(ll)sum*(nxt[j][cnt]-j))%mod;
}
}
cout<<ans;
return 0;
}
本文在写作完成后使用 DeepSeek 进行了润色。