关于一类容斥原理设计 dp 状态的探讨

写在前面

为什么要写?因为自己学不明白希望日后能掌握。

下列所有类似 \([l,r]\) 这样的都是离散的。

1.

\(n\) 个点,每个点有一个能选择的颜色 \(a_i\),左右相邻的点不能同色,求方案数。

如果我们使用容斥的思想,强制 \(k\) 段的颜色相同,这个限制下的方案数对答案的贡献的容斥系数就是 \((-1)^{n-k}\)。这应该是相邻颜色不同的方案数的一个非常平凡的trick。(但是我不会

可以设 \(f_i\) 表示统计到前 \(i\) 个点所容斥的答案和。枚举 \([j,i]\) 这一段强制颜色相等。

\[f_i=-\sum\limits_{j=1}^i f_{j-1}\min\limits_{j\le k\le i}a_i \]

这个东西可以用单调栈维护一下。

注意到这个东西可以拓展到环上。把 \(a_i\) 最小的位置轮换到最前面,然后你发现 \(f_i\) 其实就是强制了 \([i+1,n]\)和 \(1\) 的颜色相同的答案。全部加起来就好了。

    s[0] = f[0] = 1; int top = 0;
    ll sum = 0;
    fo(i, 1, c) {
        while(top && b[stc[top]] > b[i])
            sum = (sum + (ll)(s[stc[top] - 1] - (stc[top] == 1 ? 0 :
                  s[stc[top - 1] - 1]) + mod) * (b[i] - b[stc[top]] + mod)) % mod,
            --top;
        stc[++top] = i;
        sum = (sum + (ll)f[i - 1] * b[i]) % mod;
        f[i] = mod - sum;
        s[i] = (f[i] + s[i - 1]) % mod;
    }

2.

\(n\) 个点,一个区间可以覆盖 \([l_i,r_i]\) 这一段,每个区间有一个价值 \(v_i\) ,定义一种“覆盖”为每个点至少被一个区间所覆盖的方案,其价值为所有所选区间的价值积,求所有覆盖的价值之和。

考虑强制 \(k\) 个点不被覆盖,那么这种情况对答案的贡献的容斥系数就是 \((-1)^k\)。其贡献就是这些点之间的区间的乘积之和。

这样的话,设 \(f_i\) 表示 \(i\) 点被钦定,枚举 \(j\) 表示上一个钦定点,有

\[f_i=-\sum_{j=1}^{i-1}f_j \prod_{j<l_k\le r_k<i}(v_k+1) \]

这玩意可以线段树优化!考虑线段树的每一个位置记录的是它作为 \(j\) 造成的贡献,假设现在新加入一个区间 \(k\) ,它能使 \([0,l_k)\) 的位置的贡献发生变化,乘上 \((1+v_k)\)。

代码要稍等。

To be continue..

上一篇:STC单片机烧录时的坑不要踩


下一篇:ext4 fs lookup