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

 

posted @ 2013-11-21 12:18  valaxy  阅读(259)  评论(0编辑  收藏  举报