传送门
注意到 $m$ 只有 $20$ ,考虑一下状压 $dp$
设 $f[S]$ 表示当前确定的字符集合为 $S$ ,那么转移就考虑从最右边加入的下一个字符 $c$
那么问题来了,代价如何计算
考虑每次加入一个字符以后对于所有字符间的移动$(c_i,c_{i+1})$产生的代价
那么显然只有当 $c_i \in S$ ,$c_{i+1} \notin S$ 时,移动 $(c_i,c_{i+1})$ 会多经过当前加入的字符的位置,那么需要的时间就会增加 $1$
所以我们可以维护一个 $cnt[i][j]$ 表示 $c_{i}=i,c_{i+1}=j$ 的移动数量
那么每次转移代价可以直接 $m^2$ 枚举所有 $c_{i} \in S$ ,$c_{i+1} \notin S$ 的移动求出
这样复杂度是 $m^2 \cdot 2^m$ 算一下发现达到了 $4 \cdot 10^8$ 级别,时间限制 $1s$,显然很有问题
那么现在有两种选择,优化算代价的速度,或者用信仰直接交复杂度不对的代码
然后你发现信仰是对的,卡着时限是可以过的....比如这位神仙:https://codeforces.com/contest/1238/submission/62149786
四个点 $997ms$ 一个点 $998ms$ $\text{Orz}$
但是我没有信仰
来考虑一下如何快速计算代价,设 $h[S]$ 表示所有 $c_i \in S$ ,$c_{i+1} \notin S$ 的移动的数量
再设 $g[p][S],p \notin S$ 表示 $c_i=p , c_{i+1} \in S$ 的移动的数量
那么有 $h[S] = \sum_{p \in S} g[p][U\text{^}S]$ ,其中 $U$ 是全集
现在考虑计算 $g$ ,如果对于每个 $p,S$ 都枚举所有 $p' \notin S$ 再累加显然太慢了
注意到 $S$ 的子集 $S'$ 的代价 $g[p][S']$ 一定会加入到 $g[p][S]$ 中,那么对于 $S$ 直接枚举某一位选择的 $p'$
设 $S'|(1< 有 $g[p][S]=g[p][S']+cnt[p][p']$ 然后现在又有一个小问题,要对所有 $S$ 求出某一个为 $1$ 的位置 考虑树状数组的操作, $x&-x$ 就是 $x$ 的第一位 $1$ 的值 最后维护 $pos[x]$ 表示值为 $x=(1<
然后这一题就解决了,复杂度 $O(m \cdot 2^m)$ continue;
g[p][o]=g[p][o-(o&-o)]+cnt[p][pos[o&-o]];
}
for(int o=0;o o];
for(int o=0;o continue;
f[o^(1< 1< h[o]);
}
printf("%d\n",f[mx]);
return 0;
} #include