2019 ICPC徐州现场赛 A. Cat 思维规律题

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;
}
发布了157 篇原创文章 · 获赞 146 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_43857314/article/details/103441295
今日推荐