zoukankan      html  css  js  c++  java
  • Codeforces 460D Little Victor and Set --分类讨论+构造

    题意:从区间[L,R]中选取不多于k个数,使这些数异或和尽量小,输出最小异或和以及选取的那些数。

    解法:分类讨论。

    设选取k个数。

    1. k=4的时候如果区间长度>=4且L是偶数,那么可以构造四个数(L,L+1,L+2,L+3),这样的话(L^(L+1)) ^ ((L+2)^(L+3)) = 0,最优

    如果L不是偶数,那么看从L+1到R有没有四个数,如果有则取该四个数,否则最小异或和达不到0,也达不到1了,不再考虑k=4,k=3时还有可能等于0,所以转到k=3

    2. k=3时,要使异或和为0,那么要选取a,b,c,设a<b<c,三个数至少两位表示,且不能为0,所以我们这么构造:

    11000...

    10111...

    01111...

    因为 c 应尽量小,所以后面补0,那么下面两个后面全部补1.

    我们枚举一个一个加位数,看是否有R>=c>a>=L,如果有,那么最小异或和为0,如果没有,那么异或和就最小是1了,如果有大于等于三个数的话,我们取两个数就能达到1(一定可以以偶数开头),所以此时取三个一定不比取两个更优,所以k=2就能解决,转k=2

    3. k=2时,看有没有偶数开头的两个数(2x,2x+1),这时异或和为1,已经是当下最小的了,否则就只能比较L和L^R的大小再输出了。

    4. k=1, 显然只能取一个数的时候,选的越小越好,选L

    可以证明,k > 4的情况,一定可以通过取k<=4个达到异或和最小。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #define lll __int64
    using namespace std;
    #define N 100107
    
    int main()
    {
        lll l,r;
        int k;
        while(scanf("%I64d%I64d%d",&l,&r,&k)!=EOF)
        {
            if(k >= 4) {              //0
                if(l%2 && r-l+1 >= 5) {
                    printf("0
    4
    %I64d %I64d %I64d %I64d
    ",l+1,l+2,l+3,l+4);
                    continue;
                }
                else if(l%2 == 0 && r-l+1 >= 4) {
                    printf("0
    4
    %I64d %I64d %I64d %I64d
    ",l,l+1,l+2,l+3);
                    continue;
                }
                k = 3;
            }
            if(k == 3) {                //0
                lll c = 3LL, b = 2LL, a = 1LL;
                int flag = 0;
                while(1) {
                    if(c <= r && a >= l) { flag = 1; break; }
                    if(c > r) break;
                    a = a<<1|1;
                    b = b<<1|1;
                    c = c<<1;
                }
                if(flag) {
                    printf("0
    3
    %I64d %I64d %I64d
    ",a,b,c);
                    continue;
                }
                k = 2;
            }
            if(k == 2) {                 //1
                int flag = 0;
                for(lll i=l;i<=l+1;i++) {
                    if(i%2LL == 0 && i+1LL <= r) {
                        flag = 1;
                        printf("1
    2
    %I64d %I64d
    ",i,i+1LL);
                    }
                }
                if(!flag) {
                    if((l^r) < l)  printf("%I64d
    2
    %I64d %I64d
    ",l^r,l,r);
                    else         printf("%I64d
    1
    %I64d
    ",l,l);
                }
            }
            if(k == 1) {                      //unkown
                printf("%I64d
    1
    %I64d
    ",l,l);
                continue;
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    《那些年,我们拿下FPGA》做笔记
    三种初始化
    hdu4417 Super Mario 树阵离线/划分树
    【设计模式】文章摘要 查找联系人控件
    STL set
    阐述 QUEST CENTRAL FOR DB2 八罪
    使用线程执行堆栈StackTraceElement设计Android日志模块
    苹果iOS苹果公司的手机用户都有权索赔
    Android 4.4 沉浸式透明状态栏与导航栏
    常见的几种RuntimeException
  • 原文地址:https://www.cnblogs.com/whatbeg/p/4229714.html
Copyright © 2011-2022 走看看