zoukankan      html  css  js  c++  java
  • [AGC041F] Histogram Rooks

    容斥好题!神Itst!

    题意简述:给一个长度为 (n) ,高度不均的棋盘,第 i 列高度为 (h_i) ,你可以在棋盘上放置车(车可以直着走或横着走,但不能越过棋盘中间的空),称一个位置被控制,当且仅当其通过棋盘上的格子能被至少一个车到达

    求有多少放置车的方案,使得每个位置都被控制

    (n leq 400,h_i ge 1)

    solution

    看到每个位置都被覆盖,考虑容斥

    一个朴素的想法是,我们可以钦定若干个位置(以下我们称这种点为关键点)的集合 (U) 没有被控制,然后计算在此前提下可以放车的位置 (p) ,那么贡献便是 ((-1)^{|U|} * 2 ^ p)

    考虑如何优化这个容斥, 注意到因为列总是连续的,所以如果一个列有一个位置是关键点,那么整个列都不能放车

    考虑枚举至少有一个关键点的位置的集合 S

    那么对于每个极长行连通块,假设长度为 len ,中间在 S 内的列的数量为 p 我们的贡献就是

    • 一个关键点都不放,那么贡献是 (2 ^ {len - p})
    • 枚举放了多少关键点,贡献是 (sum_{i = 1}^p inom{p}{i}(-1)^i = -[p != 0])

    所以总贡献是两者之和

    那么我们成功将问题转化为枚举 S ,S 中的一列至少有一个关键点,每一行的贡献是 (2^{len - p} - [p != q]),总贡献是每一行贡献的积(注意我们以下考虑的是这个新问题,继续容斥也是基于这个新问题,我们可以把原问题抛掉)

    发现 S 的每一列至少有一个关键点不好处理,考虑继续容斥,根据子集反演,设 T (subseteq) S,表示 T 中的元素钦定没有关键点,容斥系数为 ((-1)^{|T|})

    那么我们继续考虑行极大连通块,我们再设一个变量 q ,表示有 q 列在 T 里面,继续讨论贡献

    • 一个关键点不放,贡献仍然是 (2 ^ {len - p})
    • 枚举放了多少关键点,贡献是 (sum_{i = 1}^{p - q} inom{p-q}{i}(-1)^i = -[p != q])

    那么我们知道 S 和 T 就可以算出贡献

    枚举 S 和 T 显然是没有前途的,我们考虑 dp ,对于这种有最小瓶颈的问题,我们考虑在笛卡尔树上 dp ,设 (f_{u,p,0/1})表示 dp 到 u 的子树, p 的值是多少, p 是否等于 q ,转移的话做树上背包即可

    复杂度 (O(n^2 log n))((log n) 是因为要做快速幂,如果预处理可以省去)

    #include <bits/stdc++.h>
    using namespace std;
    int read() {
    	char c = getchar();
    	int x = 0;
    	while(c < '0' || c > '9')		c = getchar();
    	while(c >= '0' && c <= '9')		x = x * 10 + c - 48,c = getchar();
    	return x;
    } 
    const int _ = 1e3 + 7;
    int f[_][_][2],g[_][2];
    int st[_][21];
    int lg2[_];int n;int h[_],fa[_],len[_];
    int siz[_];
    vector<int>E[_];
    #define pb push_back
    #define mod 998244353
    bool cmp(int x,int y) {
    	if(h[x] == h[y])	return x < y;
    	return h[x] < h[y];
    }
    int Min(int x,int y) {
    	if(cmp(x,y))	return x;
    	return y;
    }
    void rmq() {
    	int t = lg2[n];
    	for (int i = 1; i <= t; ++i) {
    		for (int j = 1; j + (1 << i) - 1 <= n; ++j)
    			st[j][i] = Min(st[j][i-1],st[j+(1<<(i-1))][i-1]);
    	}
    }
    int ask(int l,int r) {
    	int k = lg2[r - l + 1];
    	return Min(st[l][k],st[r-(1<<k)+1][k]);
    }
    int build(int l,int r) {
    	if(l > r)	return 0;
    	int mid = ask(l,r);
    	int lc = build(l,mid - 1);
    	int rc = build(mid + 1,r);
    	if(lc)	fa[lc] = mid,E[mid].pb(lc);
    	if(rc)	fa[rc] = mid,E[mid].pb(rc);
    	len[mid] = r - l + 1;
    	return mid;
    }
    void add(int &x,int y) {
    	x += y - mod;
    	x += (x >> 31) & mod;
    }
    int qpow(int x,int y) {
    	int ans = 1;
    	while(y) {
    		if(y & 1)	ans = 1ll * ans * x % mod;
    		x = 1ll * x * x % mod;
    		y >>= 1;
    	}
    	return ans;
    }
    void treedp(int u) {
    	f[u][0][1] = 1;/*equal:1,otherwise 0*/
    	f[u][1][1] = mod - 1;
    	f[u][1][0] = 1;
    	int H = h[u] - h[fa[u]];
    	siz[u] = 1;
    	for (auto v:E[u]) {
    		treedp(v);
    		for (int i = 0; i <= siz[u]; ++i) {
    			g[i][0] = f[u][i][0];
    			g[i][1] = f[u][i][1];
    			f[u][i][0] = f[u][i][1] = 0;
    		}
    		for (int i = 0; i <= siz[u]; ++i) {
    			for (int j = 0; j <= siz[v]; ++j) {
    				add(f[u][i+j][1],1ll * g[i][1] * f[v][j][1] % mod);
    				int val = 1ll * (g[i][1] + g[i][0]) % mod * (f[v][j][1] + f[v][j][0]) % mod;
    				add(val,mod - 1ll * g[i][1] * f[v][j][1] % mod);
    				add(f[u][i+j][0],val);
    			}
    		}
    		siz[u] += siz[v];
    	}
    	for (int p = 0; p <= len[u]; ++p) {
    		int v = qpow(2,len[u] - p);
    		f[u][p][1] = 1ll * f[u][p][1] * qpow(v,H) % mod;
    		add(v,mod - 1);
    		f[u][p][0] = 1ll * f[u][p][0] * qpow(v,H) % mod;
    	}
    }
    int main() {
    	n = read();
    	for (int i = 1; i <= n; ++i)	h[i] = read();
    	for (int i = 1; i <= n; ++i)	st[i][0] = i;
    	for (int i = 2; i <= n; ++i)	lg2[i] = lg2[i>>1] + 1;
    	rmq();
    	int rt = build(1,n);
    	treedp(rt);
    	int ans = 0;
    	for (int p = 0; p <= n; ++p) {
    		add(ans,(1ll * f[rt][p][0] + f[rt][p][1]) % mod);
    	}
    	cout << ans << '
    ';
    	return 0;
    }
    
  • 相关阅读:
    Android兼容性测试CTS
    Tkinter
    初探socket
    性能监控2
    HTTP
    python实现接口自动化1
    pip安装超时问题
    一行 Python
    Python 面向对象进阶
    Python 面向对象编程基础
  • 原文地址:https://www.cnblogs.com/y-dove/p/14851602.html
Copyright © 2011-2022 走看看