20

http://pjudge.ac/contest/1288/problem/21777

考虑 A 性质怎么做,把每种颜色从 \(x\) 轴上面还是下面连过去视作 \(0/1\) 两种状态,然后优化建图跑二分图染色即可。

如果在一般情况沿用上面的做法,对合法性的刻画会变得十分复杂,因为两个点之间的连边可能会从整个数轴的左边或右边绕过去。但是我们发现,如果可以从左边绕过去,那也一定可以改成从右边绕过去,而不改变整个连边方式的合法性,如下图。

这启发我们,上面做法里的刻画方式是很不对的,因为经过这样一次改变,\(0/1\) 状态就变了。

考虑在这样一次改变里,什么东西没有变。从一个点延申出的线段方向是没有变的。所以设 \(x_i\) 表示点 \(i\) 延申出的线段方向,经过一些手玩,所有对合法性的刻画都可以写成如下形式:

  • \(l_i<l_j<r_j<r_i\),则 \(x_{l_j}=x_{r_j}\)
  • \(l_i<l_j<r_i<r_j\),则 \(x_{l_j}\not=x_{r_i}\)

然后就做完了。

https://newoj.daimayuan.top/p/4775?tid=69a5374fbff5d4356a21b04f

问题可以变成这样:有 \(n\) 个长度为 \(n\) 的 bitset,你需要对于每一位,求出有多少个 bitset 上这一位为 \(1\)

\(n\) 个 bitset 做分治,拆位模拟加法。

vector<int> solve(int l, int r) {
    if (l == r) return {s[l]};
    int mid = l + r >> 1, tmp = 0;
    vector<int> sl = solve(l, mid), sr = solve(mid + 1, r), ans;
    int mx = max(sl.size(), sr.size());
    sl.resize(mx), sr.resize(mx), ans.resize(mx);
    for (int i = 0; i < sl.size(); i++) {
        ans[i] = sl[i] ^ sr[i] ^ tmp;
        tmp = (sl[i] & sr[i]) | ((sl[i] | sr[i]) & tmp);
    }
    if (tmp) ans.push_back(tmp);
    return ans;
}

https://loj.ac/p/6729

\(f_{S,i}\) 表示集合 \(S\) 内的点组成的连通图,\(1\sim i\) 全都不是割点的方案数。那么有

\[f_{S,0}=2^{cnt_S}-\sum_{\min(S)\in T}f_{T,0}2^{cnt_{S-T}} \]

\[f_{S,i}=f_{S,i-1}-\sum_{i\in T,\min(S-\set i)\in T}f_{T,i}f_{(S-T)\cup\set i,i-1}\ \]

答案就是 \(f_{S,n}\)

https://loj.ac/p/6730

注意到边双是由若干个大小不为 \(2\) 的点双拼起来组成的。设 \(g_{S,i}\) 表示集合 \(S\) 内的点组成的边双连通图,已经加入了 \(i+1\sim n\) 的割点的方案数,那么有

\[g_{S,n}=[|S|\not=2]f_{S,n} \]

\[g_{S,i-1}=g_{S,i}+\sum_{i\in T,\min(S-\set i)\in T}g_{T,i}g_{(S-T)\cup\set i,i-1}\ \]

答案就是 \(g_{S,0}\)

这完全就是把上面那个题的过程倒过来做了一遍。

posted @ 2026-03-02 16:36  Egg_eating_master  阅读(24)  评论(0)    收藏  举报