<span>模拟48 题解</span>
A. String Master
$O(n^3)$随便做。
B. Tourist Attractions
因为数据范围$n^2$没有任何问题。
考虑设$dp(i,j,k)$表示节点i从节点j来,并再走k步的方案数。
显然$dp(i,j,1)=du(i)-1$,除了返回j,别的方案都是可行的。
设$link(i,j)$表示i,j是否联通的0/1变量。
$dp(i,j,2)=\sum \limits_{k,link(i,k)}dp(k,i)-link(k,j)$,当k可以走回j的时候,可能造成重复计数,故减去。
$dp(i,3)=\sum \limits_{k,link(i,k)}dp(k,i)$
$ans=\sum \limits_{i=1}^{n}dp(i,3)$
瓶颈在于如何求$dp(i,j,2)$,暴力求是$O(n^3)$的。
不妨将式子中加和减的两项拆开,那么发现bitset维护一下i走到k再走到j的方案数就可以了。
C. Walk
70分暴力,每个值只在bfs第一次出现时,更新一遍它的所有子集。
枚举子集的复杂度是$O(3^k)$的。(k为val二进制下最大的位数)
问题在于如何将$3^k$的边转化为$2^k$级别。
考虑由每个权值向1的个数减少1的权值建边权为0的边,那么边的个数为$k*2^k$级别。
由点向权值建边权为0的边,权值向对应的点建权值为1的边。
因为权值只有0/1两种形式,双端队列bfs。
另外,如果点向权值建边权为1的边,权值向点建权值为0的边。
这样进行bfs是错误的,原因是可能导致点被提前更新更大的答案。
另外记录一道与本题稍有一点关系的特殊的题目(LadyLex学长的课件):
有$2^{20}$个元素,每次使某元素对给定值取$max$,求某个数代表的二进制的子集中元素的最大值。
有这样的状态定义:$F[i][j]$代表“状态s的前一半数位为i的子集,后一半数位为j”的方案数/最小值等信息。
这样在更新和查找的时候,我们都只需要枚举一半的数位(查找枚举j的子集,更新枚举i的超集),从而给状压那一块的复杂度开了个根号。