1. 程式人生 > 其它 >關於一類容斥原理設計 dp 狀態的探討

關於一類容斥原理設計 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..