题解:P17731 [ICPC 2019 Xuzhou R] Cat
题解:P17731 [ICPC 2019 Xuzhou R] Cat
题意
有编号为
其中
有
考场思路
求一段区间的异或和自然想到前缀异或。设:
那么区间
经过手模前几项,不难发现前缀异或的一个规律:
于是如果存在两个前缀下标
于是,
正解思路
由此我们能发现:
对于任意长度不小于
7 的区间,一定存在一个长度至少为len-6 的子区间,其异或和为0 。
因为在前缀下标序列中,模
也就是说,如果原区间长度为
因此对于
对于某个长度,我们可将其视为去掉
其花费为:
若花费不超过
对于
代码
#include<bits/stdc++.h>
#define lowbit(x) (x&-x)
#define fi first
#define se second
#define pct(x) __builtin_popcount(x)
#define ump unordered_map<int,int>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=2e5+5,K=55,INF=0x3f3f3f3f,mod=998244353;
ll f(ll n){
if(n%4==0)return n;
if(n%4==1)return 1;
if(n%4==2)return n+1;
if(n%4==3)return 0;
}
ll l,r,s,len,ans;
void solve(){
cin>>l>>r>>s;
len=r-l+1,ans=-1;
if(len<7){
for(int i=len,fl;i>=1;i--){
fl=0;
for(ll j=l;j+i-1<=r;j++){
if((f(j+i-1)^f(j-1))<=s){
fl=1;
break;
}
}
if(fl){
ans=i;
break;
}
}
}
else{
for(int i=0,fl;i<=6;i++){
fl=0;
for(int j=0;j<=i;j++){
if((f(r+j-i)^f(l+j-1))<=s){
fl=1;
break;
}
}
if(fl){
ans=len-i;
break;
}
}
}
cout<<ans<<"\n";
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
int T;
cin>>T;
while(T--)solve();
return 0;
}
复杂度分析
单次询问最多检查