[Codeforces460D] Little Victor and Set(构造)

10 篇文章 0 订阅

题目描述

传送门
题意
给定一个区间l,r与一个数k.
在l~r中找不超过k个数(不能重复选),使得这些数的异或和最小,输出方案.
1<=l<=r<=10^12,k<=10^6

题解

分几种情况讨论。
1:r-l+1<=4。
2:k=1。
3:k=2。
4:k>=4。
5:k=3。
第一种情况:2^4暴力。
第二种情况:l即为解。
第三种情况:一定能构造出异或和为1的解。
第四种情况:一定能构造出异或和为0的解。
第五种情况:
首先一定能构造出异或和为1的解。
令m表示2^m大于l且最小的值。
设x=2^m-1,y=2^m+2^(m-1),z=2^m+2^(m-1)-1就是一个异或和为0的解,如果此时y>r,则答案至少是1。

代码

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define LL long long
const LL INF=1000000000000000000LL; 
LL l,r,k,mul,m,x,y,z;
LL mi[100];
LL ans,a[10],ANS[10];
int vis[10],sum;

inline void dfs(LL dep)
{
    if (dep==r+1)
    {
        LL now=0; int cnt=0;
        for (int i=1;i<=r-l+1;++i)
            if (vis[i])
            {
                a[++cnt]=i+l-1;
                now^=(i+l-1);
            }
        if (cnt>k||!cnt) return;
        if (now<ans)
        {
            ans=now;
            sum=cnt;
            for (int i=1;i<=sum;++i)
                ANS[i]=a[i];
        }
        return;
    }
    for (int i=0;i<=1;++i)
    {
        vis[dep-l+1]=i;
        dfs(dep+1);
    }
}
int main()
{
    scanf("%I64d%I64d%I64d",&l,&r,&k);
    if (r-l+1<5)
    {
        ans=INF;
        dfs(l);
        printf("%I64d\n%d\n",ans,sum);
        for (int i=1;i<=sum;++i) printf("%I64d%c",ANS[i]," \n"[i==sum]);
        return 0;
    }
    else
    {
        if (k==1)
        {
            printf("%I64d\n1\n%I64d\n",l,l);
            return 0;
        }
        if (k==2)
        {
            if (l&1) l++;
            puts("1");
            puts("2");
            printf("%I64d %I64d\n",l,l+1);
        }
        if (k>=4)
        {
            if (l&1) l++;
            puts("0");
            puts("4");
            printf("%I64d %I64d %I64d %I64d\n",l,l+1,l+2,l+3);
            return 0;
        }
        if (k==3)
        {
            mul=1; m=0;
            for(;;mul*=2,m++)
            {
                mi[m]=mul;
                if (mul>l) break;
            }
            x=mi[m]-1;
            y=mi[m]+mi[m-1]-1;
            z=mi[m]+mi[m-1];
            if (z<=r)
            {
                puts("0");
                puts("3");
                printf("%I64d %I64d %I64d\n",x,y,z);
            }
            else
            {
                if (l&1) l++;
                puts("1");
                puts("2");
                printf("%I64d %I64d\n",l,l+1);
            }
            return 0;
        }
    }
}

总结

一定要好好想!
异或和这个东西好好想!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值