關於一類容斥原理設計 dp 狀態的探討
阿新 • • 發佈:2021-10-21
寫在前面
為什麼要寫?因為自己學不明白希望日後能掌握。
下列所有類似 \([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\)
程式碼要稍等。
To be continue..