每一个状态都检索感受挺大的,标准答案的作法是每扩展一位,都挑出投诉数最小的101个方案,由于只会ban掉100个方案,因此这最小的101个里确定有能够用的python
我用了TRIE,把forbidden pattern放到一棵trie里,而后dfs这棵树,好比咱们总共10位,遍历到前缀1001
时,发现这个节点只有一个孩子(假设为"1"
),也就是说,只有10011
后面可能有被ban掉的方案,而10010
后面5位能够随咱们发挥。web
用数组f[i]
记录从第i
位到最后都随意发挥时的最小投诉数,这个DP就能够了
那么当咱们遍历到前缀prefix
,且当前前缀产生的投诉数为now
,此时要决定第i
位:数组
i
位选啥均可能被ban,分别进一步,now
分别加上两种选择的投诉数"1"
),说明第i
位选"0"
时能够直接经过f
计算结果,而选"1"
的结果须要进一步计算prefix
必定是个被ban的方案,返回一个无穷大值INF
使得这个值永远不被选上。# -*- coding:utf-8 -*- from collections import defaultdict from functools import reduce INF = 10**5 def solve(p,A,trie): f = [0]*(p+1) f[p] = 0 for i in range(p-1,-1,-1): f[i] = f[i+1]+min(A[i][0],A[i][1]) def dfs(now,i,rt): if "0" in rt and "1" in rt: return min(dfs(now+A[i][0],i+1,rt["0"]),dfs(now+A[i][1],i+1,rt["1"])) if "0" in rt: return min(now+A[i][1]+f[i+1],dfs(now+A[i][0],i+1,rt["0"])) if "1" in rt: return min(now+A[i][0]+f[i+1],dfs(now+A[i][1],i+1,rt["1"])) return INF return dfs(0,0,trie) if __name__ == "__main__" : Trie = lambda:defaultdict(Trie) END = True t = int(input()) for round in range(1,t+1): n,m,p = map(int,input().split()) A = [[0,0] for _ in range(p)] trie = Trie() for _ in range(n): string = input() for i,c in enumerate(string): if c=='1': A[i][0] += 1 else: A[i][1] += 1 for _ in range(m): reduce(dict.__getitem__,input(),trie)[END] = 1 print("Case #%d: %d"%(round,solve(p,A,trie)))