import random
def ModularSubsetSum(W, m):
p = 1234567891 #large prime ${\color{commentcolour} p > m^2 \log m}$
r = random.randint(0,p) #random number ${\color{commentcolour} r}$ in [0,p)
powr = [1] #Precompute powers of ${\color{commentcolour} r }$
for i in range(2*m): #powr[i] ${\color{commentcolour} \triangleq }$ ${\color{commentcolour} r^i }$ (mod p)
powr.append((powr[-1] * r) % p)
#Binary Indexed Tree for prefix sums
tree = [0] * (2*m)
def read(i): #Prefix sum of [0,i)
if i<=0: return 0
return tree[i-1] + read(i-(i&-i))
def update(i, v): #add v to position i
while i < len(tree):
tree[i] += v
i += (i+1)&-(i+1)
#Functions for finding new subset sums and adding them
def FindNewSums(a,b,w):
h1 = (read(b)-read(a))*powr[m-w] % p #hash of ${\color{commentcolour} S \cap [a,b)}$
h2 = (read(b+m-w)-read(a+m-w)) % p #hash of ${\color{commentcolour} (S+w) \cap [a,b)}$
if h1 == h2: return []
if b == a+1:
if sums[a] is None: return [a] #a is a new sum
return [] #a is a ghost sum
return FindNewSums(a,(a+b)//2,w) + FindNewSums((a+b)//2,b,w)
def AddNewSum(s, w):
sums[s] = w
update(s,powr[s]), update(s+m,powr[s+m])
#Main routine for computing subset sums
sums = [None] * m
AddNewSum(0,0)
for w in W:
for s in FindNewSums(0,m,w):
AddNewSum(s,w)
return sums
print(ModularSubsetSum([1,3,6], 8)) #Returns [0, 1, 6, 3, 3, None, 6, 6]
def RecoverSubset(sums, s):
if sums[s] is None: return None
if s <= 0: return []
return RecoverSubset(sums, (s-sums[s]) % len(sums)) + [ sums[s] ]
sums = ModularSubsetSum([1,3,6], 8)
print(RecoverSubset(sums, 7)) #Returns [1, 6]
print(RecoverSubset(sums, 2)) #Returns [1, 3, 6]
aW1wb3J0IHJhbmRvbQoKZGVmIE1vZHVsYXJTdWJzZXRTdW0oVywgbSk6CiAgICBwID0gMTIzNDU2Nzg5MSAgICAgICAgICAgICAgICAgICAgICAgICAgICAjbGFyZ2UgcHJpbWUgJHtcY29sb3J7Y29tbWVudGNvbG91cn0gcCA+IG1eMiBcbG9nIG19JAogICAgciA9IHJhbmRvbS5yYW5kaW50KDAscCkgICAgICAgICAgICAgICAgICAgI3JhbmRvbSBudW1iZXIgJHtcY29sb3J7Y29tbWVudGNvbG91cn0gcn0kIGluIFswLHApCiAgICBwb3dyID0gWzFdICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjUHJlY29tcHV0ZSBwb3dlcnMgb2YgJHtcY29sb3J7Y29tbWVudGNvbG91cn0gciB9JAogICAgZm9yIGkgaW4gcmFuZ2UoMiptKTogICAgICAgICAgICAgICAgICAgICAgI3Bvd3JbaV0gJHtcY29sb3J7Y29tbWVudGNvbG91cn0gXHRyaWFuZ2xlcSB9JCAke1xjb2xvcntjb21tZW50Y29sb3VyfSByXmkgfSQgKG1vZCBwKQogICAgICAgIHBvd3IuYXBwZW5kKChwb3dyWy0xXSAqIHIpICUgcCkKICAgIAogICAgCiAgICAjQmluYXJ5IEluZGV4ZWQgVHJlZSBmb3IgcHJlZml4IHN1bXMKICAgIHRyZWUgPSBbMF0gKiAoMiptKQogICAgZGVmIHJlYWQoaSk6ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI1ByZWZpeCBzdW0gb2YgWzAsaSkKICAgICAgICBpZiBpPD0wOiByZXR1cm4gMAogICAgICAgIHJldHVybiB0cmVlW2ktMV0gKyByZWFkKGktKGkmLWkpKSAKICAgIGRlZiB1cGRhdGUoaSwgdik6ICAgICAgICAgICAgICAgICAgICAgICAgICNhZGQgdiB0byBwb3NpdGlvbiBpCiAgICAgICAgd2hpbGUgaSA8IGxlbih0cmVlKToKICAgICAgICAgICAgdHJlZVtpXSArPSB2CiAgICAgICAgICAgIGkgKz0gKGkrMSkmLShpKzEpCiAgICAKICAgIAogICAgI0Z1bmN0aW9ucyBmb3IgZmluZGluZyBuZXcgc3Vic2V0IHN1bXMgYW5kIGFkZGluZyB0aGVtCiAgICBkZWYgRmluZE5ld1N1bXMoYSxiLHcpOgogICAgICAgIGgxID0gKHJlYWQoYiktcmVhZChhKSkqcG93clttLXddICUgcCAgI2hhc2ggb2YgJHtcY29sb3J7Y29tbWVudGNvbG91cn0gUyBcY2FwIFthLGIpfSQKICAgICAgICBoMiA9IChyZWFkKGIrbS13KS1yZWFkKGErbS13KSkgJSBwICAgICNoYXNoIG9mICR7XGNvbG9ye2NvbW1lbnRjb2xvdXJ9IChTK3cpIFxjYXAgW2EsYil9JAogICAgICAgIGlmIGgxID09IGgyOiByZXR1cm4gW10KICAgICAgICBpZiBiID09IGErMTogICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgaWYgc3Vtc1thXSBpcyBOb25lOiByZXR1cm4gW2FdICAgICNhIGlzIGEgbmV3IHN1bQogICAgICAgICAgICByZXR1cm4gW10gICAgICAgICAgICAgICAgICAgICAgICAgI2EgaXMgYSBnaG9zdCBzdW0KICAgICAgICByZXR1cm4gRmluZE5ld1N1bXMoYSwoYStiKS8vMix3KSArIEZpbmROZXdTdW1zKChhK2IpLy8yLGIsdykKICAgIGRlZiBBZGROZXdTdW0ocywgdyk6CiAgICAgICAgc3Vtc1tzXSA9IHcKICAgICAgICB1cGRhdGUocyxwb3dyW3NdKSwgdXBkYXRlKHMrbSxwb3dyW3MrbV0pCiAgICAKICAgIAogICAgI01haW4gcm91dGluZSBmb3IgY29tcHV0aW5nIHN1YnNldCBzdW1zCiAgICBzdW1zID0gW05vbmVdICogbQogICAgQWRkTmV3U3VtKDAsMCkKICAgIGZvciB3IGluIFc6CiAgICAgICAgZm9yIHMgaW4gRmluZE5ld1N1bXMoMCxtLHcpOgogICAgICAgICAgICBBZGROZXdTdW0ocyx3KQogICAgICAgICAgICAKICAgIHJldHVybiBzdW1zCiAgICAKcHJpbnQoTW9kdWxhclN1YnNldFN1bShbMSwzLDZdLCA4KSkgICNSZXR1cm5zIFswLCAxLCA2LCAzLCAzLCBOb25lLCA2LCA2XQoKZGVmIFJlY292ZXJTdWJzZXQoc3Vtcywgcyk6CiAgICBpZiBzdW1zW3NdIGlzIE5vbmU6IHJldHVybiBOb25lCiAgICBpZiBzIDw9IDA6IHJldHVybiBbXQogICAgcmV0dXJuIFJlY292ZXJTdWJzZXQoc3VtcywgKHMtc3Vtc1tzXSkgJSBsZW4oc3VtcykpICsgWyBzdW1zW3NdIF0KICAgIApzdW1zID0gTW9kdWxhclN1YnNldFN1bShbMSwzLDZdLCA4KQpwcmludChSZWNvdmVyU3Vic2V0KHN1bXMsIDcpKSAgI1JldHVybnMgWzEsIDZdCnByaW50KFJlY292ZXJTdWJzZXQoc3VtcywgMikpICAjUmV0dXJucyBbMSwgMywgNl0=