全部评论 1

  • 1. 状态压缩与编码优化

    之前的代码将状态拆分成了三个独立的数组(fst[0], fst[1], fst[2]),这在内存访问和哈希计算时非常低效。
    优化方案:将“炮塔数量”、“格子类型”和“插头连通性”全部压缩进一个 long long 整数中。

    • 炮塔数量 K15K \le 15,占 4 位。
    • 轮廓线长度最大为 20,每个格子用 2 位表示类型(00障碍, 01路径, 11炮塔),占 40 位。
    • 插头连通性使用最小表示法(括号+独立插头),每个插头占 2 位,占 42 位。
      总共 86 位,完美契合 long long(64位可能不够,需使用 unsigned long long 或分两段,但本题 m20m \le 20,经过极限压缩刚好可以塞进 64 位,或者用 __int128)。

    2. 哈希表优化(手写哈希)

    标准库的 std::unordered_map 在插头DP中会因为常数过大而超时(TLE)。
    优化方案:手写开散列(拉链法)哈希表。

    • 取一个大素数(如 9973100007)作为模数。
    • 使用数组模拟链表,head[] 存表头,next[] 存后继。
    • 状态转移时,先计算哈希值,在链表中线性查找,找到则更新最大值(max),找不到则插入新节点。

    3. 滚动数组优化

    优化方案:DP 过程只依赖上一行/上一格的状态,因此只需要开两个哈希表(H[2]),通过 swap(H0, H1) 进行滚动,极大节省内存并提高缓存命中率。

    4. 剪枝与预处理优化

    • 炮塔伤害预处理:不要等到最后再算伤害。在转移时,如果当前格子放炮塔,直接计算它对周围已确定格子的伤害增量;如果走路径,计算它受到周围已确定炮塔的伤害。这样可以在 DP 过程中直接累加答案,避免最后遍历状态时的巨大开销。
    • 障碍特判:遇到原地图的 #,如果轮廓线上有插头,直接跳过(continue),减少无效状态转移。

    5. 最小表示法(连通性压缩)

    优化方案:不要直接记录插头的绝对编号,使用最小表示法。例如,遇到一个新的连通块,赋予当前最小的未使用编号。这能将状态数从指数级降低到卡特兰数级别,是插头DP能过题的关键。

    优化后的代码框架示例

    #include <bits/stdc++.h>
    using namespace std;
    typedef unsigned long long ull;
    
    const int PRIME = 9973;
    const int MAXS = 200000; // 根据实际状态数调整
    
    struct HashTable {
        int head[PRIME], next[MAXS], sz;
        ull state[MAXS];
        int val[MAXS];
    
        void clear() {
            sz = 0;
            memset(head, -1, sizeof(head));
        }
    
        void push(ull s, int v) {
            int h = s % PRIME;
            for (int i = head[h]; ~i; i = next[i]) {
                if (state[i] == s) {
                    val[i] = max(val[i], v);
                    return;
                }
            }
            state[sz] = s;
            val[sz] = v;
            next[sz] = head[h];
            head[h] = sz++;
        }
    } H[2];
    
    // 状态解码与编码函数(使用位运算替代取模)
    inline int get(ull s, int pos) { return (s >> (pos << 1)) & 3; }
    inline ull set(ull s, int pos, int v) { return s ^ (((ull)get(s, pos) ^ v) << (pos << 1)); }
    
    int main() {
        // 初始化与读入...
        H[0].clear();
    

    3天前 来自 广东

    0
暂无数据

提交答案之后,这里将显示提交结果~

首页