0:21 ,回顾一下今天打的徐州重现赛叭.
题意:
T次询问
让你选择一个最长的 区间,异或小于等于 P
题目思路:
首先T是 5e5
l,r 都是1e18
嗯...确定这个题基本是个规律题
然后 放一张图:
区间异或值,发现偶数开头的区间 ,每四个就会出现一个 0,2 3 4 5 异或为0 ,6 7 8 9 异或也为0
而奇数区间没有这个规律。
重点来了,当区间长度大于等于5时,一定会出现以一个偶数开头的长度为4的区间 [抽屉定理可以证明]
所以:
1.当询问的区间小于等于4时,我们直接可以遍历该区间的所有子区间,这样的复杂度是很低的,4*4
2.当询问的区间大于4时,我们可以对区间进行压缩 :
我们将已偶数开头的连续的四的倍数的区间直接压缩到0,那么剩下的元素 最多为4个【前面一个奇数,后面没凑够长度4,余3】
比如:
【2,7】 这段区间可以压缩为集合{0,6,7}
【3,7】 这段区间可以压缩为集合{3,0} 【4,7】异或为0
所以说我们这么压缩区间之后,区间的最大长度就是5,对其进行第一步的操作即可。
注意:
(1)我们可以一定保证压缩完是最优的,因为压缩完后的结果是0
AC:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
typedef long long ll;
const int maxn=1e6+5;
using namespace std;
const ll INF=1e13+7;
const ll mod=998244353;
ll n,m,p;
ll st[maxn];
ll s=0;
void work()
{
ll maxl=-1;
ll ans=0;
if(n%2==1)
{
st[++s]=n;
ll temp=m-n;
ll cir=temp/4;
ll e=cir*4+n;
st[++s]=0;
e++;
while(e<=m) st[++s]=e++;
for(int i=1;i<=s;i++)
{
ans=0;
for(int k=i;k<=s;k++)
{
ans^=st[k];
if(ans<=p)
{
ll temp1=k-i+1;
if(2>=i&&2<=k)
temp1+=cir*4-1;
maxl=maxl>temp1?maxl:temp1;
}
}
}
}
else
{
st[++s]=0;
ll temp=m-n+1;
ll e=(temp/4)*4+n-1;
e++;
while(e<=m) st[++s]=e++;
for(int i=1;i<=s;i++)
{
ans=0;
for(int k=i;k<=s;k++)
{
ans^=st[k];
if(ans<=p)
{
ll temp1=k-i+1;
if(1>=i&&1<=k)
temp1+=(temp/4)*4-1;
maxl=maxl>temp1?maxl:temp1;
}
}
}
}
printf("%lld\n",maxl);
}
int main()
{
ll ans=0;int T;
scanf("%d",&T);
while(T--)
{
s=0;
ll maxl=-1;
scanf("%lld%lld%lld",&n,&m,&p);
if(m-n+1<=4)
{
ll ans=0;
for(ll i=n;i<=m;i++)
{
ans=0;
for(ll k=i;k<=m;k++)
{
ans^=k;
if(ans<=p)
maxl=maxl>(k-i+1)?maxl:(k-i+1);
}
}
printf("%lld\n",maxl);
}
else
work();
}
return 0;
}