zoukankan      html  css  js  c++  java
  • SRM596 DIV1 500

    逻辑分析题,先看cool的定义:

    1.1 对任意两个不同的数A和B,A&B > 0

    1.2 对任意三个不同的数A、B和C,A&B&C = 0

    分析数的二进制位可以推出以下等价定义:

    2.1 任意一对数至少有一个二进制位(下同)都为1

    2.2 考虑所有的数,任意一位上1的总数最多为2

    定义几个术语:

    位对 若A和B在w位上相等且都为1则称AB在w位上拥有一个位对(w, A, B)

    双位 在该位上1的总数为2

    单位 在该位上1的总数为1

    无效位 在该位上1的总数为0

    定义2转换为下述表述:

    3.1 任意两个数都在某位上有一个位对

    3.2 每位上最多存在一个位对

    现在新增一个集合M还要使S+M是cool的,则必须有:

    4.1 M满足条件3.1,则位对只能存在于S的无效位上

    4.2 M中的数和S中的数两两之间有位对,则位对只能存在于S的单位上

    4.3 M满足条件3.2

    因此原题变成找一个符合条件4的最小集合M

    每一位只能是无效位、单位、双位:

    无效位w上,可以任意指定M中的两个数x和y,令xy在该位为1并生成一个位对(w, x, y),而M中的其他数在该位都为0

    单位w上,可以任意指定M中的某个数x,令x在该位为1并生成一个位对(w, x, z),其中z是S中某个确定的数,M中的其他数在该位都为0

    双位使得M中所有数在该位上一定都为0。

    令M的元素个数为m,S的元素个数为s,则:

    要满足条件4.1,则必须找出S的至少 (frac{m(m-1)}{2}) 个无效位并在M中产生这么多个位对

    要满足条件4.2,则对于M的每个数x,找出s个单位并保证这些单位属于不同的S中的数,产生s个位对,每个单位只能被用一次

    要满足条件4.3,保证每位1的个数不要超过2

    要使得M最小,只要在构造的过程中选择使得数最小的位对就行了,以下方法生成一个M是从小到大排列:

    对于4.1,从小到大枚举无效位,按照字典序匹配M中的数对,只枚举 (frac{m(m-1)}{2}) 个

    对于4.2,将S中的每个数最小的单位与M中的第一个数匹配,将S中的每个数次小的单位与M中的第二个数匹配,以此类推

    对于4.3,将其他没确定的数位一律设为零

    可以证明其字典序最小

     1 class BitwiseAnd:
     2         def lexSmallest(self, subset, n):
     3                 maxLength = 60
     4                 m = len(subset)
     5                 for i in range(m):
     6                         for j in range(i+1, m):
     7                                 if subset[i] & subset[j] == 0:
     8                                         return ()
     9 
    10                 for i in range(m):
    11                         for j in range(i+1, m):
    12                                 for k in range(j+1, m):
    13                                         if subset[i] & subset[j] & subset[k] != 0:
    14                                                 return ()
    15 
    16                 bitas = [[] for i in range(m)]
    17                 bitbs = []
    18                 for i in range(maxLength):
    19                         oneCount = 0
    20                         onePlace = None
    21                         for j in range(m):
    22                                 if subset[j] >> i & 1 == 1:
    23                                         oneCount += 1
    24                                         onePlace = j
    25                         if oneCount == 1:
    26                                 bitas[onePlace].append(i)
    27                         elif oneCount == 0:
    28                                 bitbs.append(i)
    29                            
    30                 # judge
    31                 rest = n - m
    32                 for bita in bitas:
    33                         if len(bita) < rest:
    34                                 return tuple()
    35                 if len(bitbs) < rest * (rest-1) // 2:
    36                         return tuple()
    37 
    38                 # build
    39                 numbers = [0 for i in range(rest)]
    40                 for i in range(rest):
    41                         for j in range(m):
    42                                 numbers[i] |= 1 << bitas[j][i]
    43                 
    44                 i = 0
    45                 j = 0
    46                 for k in range(rest * (rest-1) // 2):
    47                         j += 1
    48                         if j == rest:
    49                                 i += 1
    50                                 j = i + 1
    51                         numbers[i] |= 1 << bitbs[k]
    52                         numbers[j] |= 1 << bitbs[k]
    53 
    54                 # create
    55                 for x in numbers:
    56                         subset += (x, )
    57                 subset = sorted(subset)
    58                 return tuple(subset)
    59 
    60 
    61 # test
    62 o = BitwiseAnd()
    63 
    64 # test case
    65 assert(o.lexSmallest((14,20), 3) == (14, 18, 20))
    66 assert(o.lexSmallest((11, 17, 20), 4) == ())
    67 assert(o.lexSmallest((99, 157), 4) == (99, 157, 262, 296))
    68 assert(o.lexSmallest((1152921504606846975,), 3) == ())
    69 assert(o.lexSmallest((), 5) == (15, 113, 402, 676, 840))
    70 assert(o.lexSmallest((1, 3, 5, 7, 9, 11), 6) == ())
    71 print('ok')
    View Code
  • 相关阅读:
    讲解SQL Server危险扩展存储删除和恢复
    新生活
    邮件发送作业调度 创建操作员
    Linux 定时任务 crontab
    短信猫二次开发接口函数及规范
    Linux修改用户shell
    Linux里$等记得转义
    网页标题前出现的图标
    Linux读书笔记
    DataStage通过分析日志获取Job插入目标表的记录数
  • 原文地址:https://www.cnblogs.com/valaxy/p/3435301.html
Copyright © 2011-2022 走看看