• CF-gym/101810 J、T-Shirts Dilemma


    题目链接:点我

     

    题意:

    给你一个区间[a,b],让你从里面选一个连续子区间[x,y](子区间可以为[a,b]),把这个区间的所有数或起来x|x+1|x+2|...|y

    你要使得区间[x,y]异或起来的结果要小于等于v。让你输出这个子区间的最大长度

     

    题解:

    我们可以先不考虑题目这个问题,换一个简单的问题:

    对于任意一个数num,找到一个最大的x,xnum,使其x|(x+1)|(x+2)||num>num

    结论:

    如果存在这样一个数x,那么num的二进制表示中的最低位的一个0,求这个0如果变成1会增加权值ans,然后x=num-ans

     

    例如num二进制为:110101,那么x=110011

    这个时候x|x+1|x+2|...|num刚好大于num,如果从x+1|x+2|...num就不会大于num(可以试试

     

    那么可以说对于可选区间[x,y],如果把y=num,那么可选区间最长长度就是num-x

     

    那么简化的问题就解决了,对于题目也就相当于可选区间[x,y]的右边界y不一定等于v,那么我们就可以枚举所有小于v的值,然后从中取最大区间就可以了

    因为我们解决问题的时候求的x是num减去num的最低位二进制表示最低位0的权值,那么对于区间[x,y]右边界y的选取可以枚举0的位置就可以了

     

    我们可以使用lowbit(~a)方式求num的最低位二进制表示最低位0的权值

    因为~a就是把a按照二进制形式每一位取反,这样的话每一位的0变成了1,1变成了0

    然后使用lowbit(b)方法求出来b的二进制下最低位1的权值

    x&(-x),当x为0时结果为0;x为奇数时,结果为1;x为偶数时,结果为x中2的最大次方的因子。

    而且这个有一个专门的称呼,叫做lowbit,即取2^k。

    代码:

    #include <map>
    #include <set>
    #include <list>
    #include <queue>
    #include <deque>
    #include <cmath>
    #include <stack>
    #include <vector>
    #include <bitset>
    #include <cstdio>
    #include <string>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <unordered_map>
    #include <unordered_set>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    inline int readint()
    {
        int tmp = 0, fh = 1;
        char c = getchar();
        while (c < '0' || c > '9')
        {
            if (c == '-') fh = -1;
            c = getchar();
        }
        while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar();
        return tmp * fh;
    }
    inline long long readll()
    {
        long long tmp = 0, fh = 1;
        char c = getchar();
        while (c < '0' || c > '9')
        {
            if (c == '-') fh = -1;
            c = getchar();
        }
        while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar();
        return tmp * fh;
    }
    ull lowbit(ull x) //求一个数二进制中的最低位1的数值
    {
        return -x & x;
    }
    ll min(ll a,ll b)
    {
        if(a<b) return a;
        else return b;
    }
    ll max(ll a,ll b)
    {
        if(a>b) return a;
        else return b;
    }
    int main()
    {
        //printf("%lld
    ",1ll<<62);
        int t;
        scanf("%d",&t);
        while(t--)
        {
            ll a,b,v,len1=0,len2=0;
            scanf("%lld%lld%lld",&a,&b,&v);
            for(int i=0;i<=62;++i) //1左移62位都1e19呢
            {
                if((1ll<<i)&b)
                    len1=i;
                if((1ll<<i)&v)
                    len2=i;
            }
            if(len2>len1)
            {
                printf("%lld
    ",b-a+1);
                continue;
            }
            if(v<a)
            {
                printf("0
    ");
                continue;
            }
            ll ans=0;
            ull res=v;
            while(1)
            {
                ull l;  //因为我们要求出来res的最低二进制位0的权值,所以需要取反
                ull tmp=lowbit(~res);
                if(res>=tmp)
                {
                    l=res-tmp;
                }
                else l=a-1;
                ans=max(ans,min(res,b)-max(l,a-1));
                printf("%lld***
    ",ans);
                res=l;
                if(a>res) break;
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    MySQL约束条件
    MySQL基本数据类型
    MySQL基本sql语句,存储引擎,创建表的语法,严格模式
    MySQL环境变量配置及系统服务制作,设置及修改密码,跳过授权表并重置密码,统一编码
    数据库及SQL语句由来,重要概念介绍,MySQL安装,启动服务端及连接,初识SQL语句
    图书管理系统前端页面搭建
    Bootstrap组件2
    c#版工作流之流程发起(3)
    C#版工作流运行机制(1)
    c#版本工作流引擎状态机(2)
  • 原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/13930316.html
Copyright © 2020-2023  润新知