zoukankan      html  css  js  c++  java
  • 【xsy1281】 珠串 打表+乱搞or数位dp

    题目大意:你要找出一个有$k$个的本质不同的$n$位二进制数的集合,使得集合中最大的数最小,请输出这个数

    本质不同定义:对于一个数$k$,$rev(k)$,$~k$,$rev(~k)$与$k$本质相同。其中$~k$表示对$k$的每一位二进制翻转,$rev(k)$表示对$k$左右翻转。

    举个例子:对于数0001,它与1000,1110,0111本质相同。

    数据范围:$n≤25,k≤10^{16}$。

    此题貌似正解是数位dp,然而我比较菜。

    看到这一题:打表啊!

    于是打了个表,发现:

    若$k≤2^{lceil frac{n}{2} ceil}-2$,则直接输出$k$就可以了,证明显然。

    若$k>2^{lceil frac{n}{2} ceil}-2$

     

    先考虑$n$为偶数的情况,我们打一个表,打出所有满足$rev(x)<x$或$(~x)<x$或$rev(~x)<x$的数,大概长这样

    我们发现:以中间的分界线为界,当左侧构成的数去掉前导零后构成$x$,那么以$x$开头的不符合要求的二进制数就有$2x$个。

    (感兴趣的同学可以证明一下,我懒得证了23333)

    我们基于这一个特征,先确定这个二进制数的前$frac{n}{2}$位。

    后面的$frac{n}{2}$位直接暴力枚举然后再随便判断一下就好了。

    n为奇数的情况相似

    以中间为分界线,当右侧横线左侧的数为$x$时,以$x$为前缀的$n$位二进制数有$x$个。

    和之前的搞法一样随便搞一搞就可以了。

    时间复杂度:$O(2^{n/2})$,空间复杂度:$O(2^{n/2})$。

     1 #include<bits/stdc++.h>
     2 #define L long long
     3 using namespace std;
     4 
     5 int rev[1<<25]={0};
     6 L n,k;
     7 
     8 void out(L k1){for(L i=0;i<n;i++) printf("%d",bool((1LL<<(n-i-1))&k1));}
     9 
    10 void SolveEven(){
    11     L n2=n/2,s=1<<n2,all=1LL<<n;
    12     if(k<s){
    13         out(k);
    14         return;
    15     }else k-=s;
    16     for(int i=1;i<s;i++) rev[i]=(rev[i>>1]>>1)|((i&1)?(s>>1):0);
    17     for(int i=1,j=2;i<s;i++,j+=2){
    18         if(k>=s-j) k-=s-j;
    19         else{
    20             int p; for(p=0;p<s&&k>=0;p++){
    21                 L k1=(1LL*i)<<n2|p;
    22                 L k2=(1LL*rev[p])<<n2|rev[i];
    23                 L k3=(1LL*rev[(s-1-p)&(s-1)])<<n2|rev[s-1-i];
    24                 if(k2>=k1&&k3>=k1) 
    25                 k--;
    26             }
    27             L k1=(1LL*i)<<n2|(p-1);
    28             out(k1);
    29             return;
    30         }
    31     }
    32     cout<<-1<<endl;
    33 }
    34 void SolveOdd(){
    35     L n2=n/2,s=1<<n2,all=1LL<<n;
    36     L N2=(n+1)/2,S=1<<N2;
    37     if(k<S-1){
    38         out(k);
    39         return;
    40     }else k-=S-1;
    41     for(int i=1;i<s;i++) rev[i]=(rev[i>>1]>>1)|((i&1)?(s>>1):0);
    42     for(int i=2,j=2;i<s;i++,j++){
    43         if(k>=s-j) k-=s-j;
    44         else{
    45             int p; for(p=0;p<s&&k>=0;p++){
    46                 L k1=(1LL*i)<<n2|p;
    47                 L k2=((i&1)<<n2)|((1LL*rev[p])<<N2)|rev[i>>1];
    48                 L k3=(((i&1)==0)<<n2)|((1LL*rev[(s-p-1)&(s-1)])<<N2)|rev[s-1-(i>>1)];
    49                 if(k2>=k1&&k3>=k1)
    50                 k--;
    51             }
    52             L k1=(1LL*i)<<n2|(p-1);
    53             out(k1);
    54             return;
    55         }
    56     }
    57     cout<<-1<<endl;
    58 }
    59 
    60 int main(){
    61     cin>>n>>k;
    62     if(n&1) SolveOdd();
    63     else SolveEven();
    64 }
  • 相关阅读:
    低版本ie模式 360兼容模式的兼容性调节以及控制代码
    360浏览器兼容模式样式乱码的原因及解决办法
    iOS开发之UILabel
    代码大全--第六章--可以工作的类
    读书笔记--软件项目成功之道
    extern "C"的用法解析(转)
    基于Ubuntu 15.04 LTS编译Android5.1.0源代码 (转)
    Global.asax 文件是什么(转)
    设备扩展(DEVICE_EXTENSION)
    IRP_MJ_CREATE
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/10519476.html
Copyright © 2011-2022 走看看