• Codeforces Round #735 (Div. 2)


    这次的cf依旧掉分.....

    A题和B题在不懈死磕下瞎搞出来了,不过还是被C题卡住了...

    C. Mikasa

    简述题意就是给定n和m,让n^0,n^1,n^2...,n^m,求着m+1个数中没有出现过的最小的非负整数.假设答案为x,则n^k=x,则k>m,我们还可以转化成n^x=k>m,也就是说我们要找一个最小的数x使得n^x>m

    若n>m,不难发现x为0就满足题意.之后考虑n<=m的情况:我们考虑一个数比另一个数大在二进制上是什么体现,比如x>y,那么我们把他们都写成二进制数,那么一定存在一个位数使得在这个位数之前x与y的二进制数是相等的,在这个位数上x>y,即x=1,y=0,只要满足这个条件,这个位数之后随意,x一定大于y,那我们考虑这里的n^k>m的情况,我们可以先把n和m写成二进制数,对于k来说,我们要求它尽可能小,但n^k必须大于m,那我们就考虑n^k要在哪一位上大于m,对于n和m的每一位,从m开始讨论,若m这一位为1,则n^k无论如何都无法在这一位上实现大于m的目标,并且我们要求n^k要大于m,那么在这一位上n^k也必须是1,期望在之后的某一位上大于m的目标,所以无论n的这一位是0还是1,我们的k的这一位与n、的这一位异或必须是1,这样的k的这一位就是确定的。若m的这一位是0,若n=1,可以发现k=0,n^k=1>0,即可完成超越m的目标并且k也没有增大,这是我们优先选择的目标,因为在某一位上超越m之后,后面的位数无论怎样都可以,所以这样的位(m=0,n=1)在越靠前,我们得到的k就越小,我们可以从最高位往下扫来确定有没有这样的位数。考虑m=.0,n=0的情况,我们有两种选择,将k赋为0,没有增加k的值,但却只能在后面超越m,还有一种选择就是令k=1,在这一位上选择超越m,之后的就不用考虑了,很显然,若有多个这样的位的话,我们肯定是让前面这样的位为0,在最后一个这样的位上为1超越m,因为k的二进制中1越在后面肯定越小。致此整个分析过程结束,我们只需要做如下操作。

    首先从最高位往下扫,看有没有m=0,n=1的位,若有,从最高位到这一位,若m=1,我们令构造k使得n^k=1,若m=0,令k=0,结束。

    若无m=0,n=1的位,从最低位到最高位扫,看有没有m=0,n=0的位,是第一个扫到的位终点,重新从最高位开始扫到终点,重复上面的赋值法则。

    //不等,不问,不犹豫,不回头.
    #include<bits/stdc++.h>
    #define _ 0
    #define ls p<<1
    #define db double
    #define rs p<<1|1
    #define RE register
    #define P 1000000007
    #define ll long long
    #define INF 1000000000
    #define get(x) x=read()
    #define PLI pair<ll,int>
    #define PII pair<int,int>
    #define ull unsigned long long
    #define put(x) printf("%d
    ",x)
    #define putl(x) printf("%lld
    ",x)
    #define rep(x,y,z) for(RE int x=y;x<=z;++x)
    #define fep(x,y,z) for(RE int x=y;x>=z;--x)
    #define go(x) for(RE int i=link[x],y=a[i].y;i;y=a[i=a[i].next].y)
    using namespace std;
    
    inline int read()
    {
        int x=0,ff=1;
        char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*ff;
    }
    
    int main()
    {
    //    freopen("1.in","r",stdin);
        int get(T);
        while(T--)
        {
            int get(n),get(m);
            if(n>m) {puts("0");continue;}
            int id=-1,ans=0;
            fep(i,30,0) //先找有没有m=0,n=1的位. 
            {
                int s1=(m&1<<i)?1:0;
                int s2=(n&1<<i)?1:0;
                if(!s1&&s2) {id=i;break;} 
            }
            if(id!=-1) //存在m=0,n=1的位数. 
            {
                fep(i,30,id)
                {
                    int s1=(m&1<<i)?1:0;
                    int s2=(n&1<<i)?1:0;
                    if(s1) ans+=(s1^s2)<<i;
                }    
            }
            else//不存在m=0,n=1的位数. 
            {
                rep(i,0,30) //找最低位的m=0,n=0的位 
                {
                    int s1=(m&1<<i)?1:0;
                    int s2=(n&1<<i)?1:0;
                    if(!s1&&!s2) {id=i;break;}
                }
                fep(i,30,id)
                {
                    int s1=(m&1<<i)?1:0;
                    int s2=(n&1<<i)?1:0;
                    if(s1) ans+=(s1^s2)<<i;
                    if(i==id) ans+=1<<i;
                }
            }
            put(ans);
        }
        return (0^_^0);
    }
    //以吾之血,铸吾最后的亡魂.
    View Code
  • 相关阅读:
    bzoj3687
    bzoj1930
    splay启发式合并
    学习笔记::启发式合并
    bzoj1798
    java提高篇(三)-----理解java的三大特性之多态
    java提高篇(二)-----理解java的三大特性之继承
    队列的顺序实现(循环数组)与链式实现
    java提高篇(一)-----理解java的三大特性之封装
    设计模式读书笔记-----解释器模式
  • 原文地址:https://www.cnblogs.com/gcfer/p/15080652.html
Copyright © 2020-2023  润新知