UOJ422 小Z的礼物

小Z的礼物

小Z有一个神奇的自动售货机,里面有 \(n \times m\) 种物品,分别放在 \(n\)\(m\) 列个格子中。每当小Z向自动售货机中投入一枚硬币,他就能获得一对相邻格子中的物品(已经获得的物品可能再次获得),获得每一对相邻格子中的物品的概率是相等的。在这 \(n \times m\) 种物品中,有一些物品是小Z喜欢的(小Z喜欢的用 * [星号] 表示,其他的用 .[英文句号] 表示),他想把这些物品包装成一份礼物。小Z想知道,期望投入多少枚硬币后,就可以获得这些他喜欢的物品。

对于所有数据,保证 \(1 \leq n \leq 6, 2 \leq m \leq 100\)

题解

一眼就能看出是min-max容斥。

\[\sum_{T\subseteq S}(-1)^{|T|+1}\frac{all}{F(T)} \]

其中 \(all=n(m-1)+m(n-1)\) 表示多米诺骨牌总数。\(F(T)\) 表示能覆盖 \(T\) 中至少一个点的多米诺骨牌数量。

考虑设计DP求出所有 \(F(T)=x\)\(T\) 的容斥系数 \((-1)^{|T|+1}\) 和。向 \(T\) 中加入一个星号时可以向四周摆放多米诺骨牌,两个相邻的星号会算重,所以我们需要用状压记录选择情况。

\(dp(i,j,S,T,x)\) 表示做到格子 \((i,j)\),前一列的星号选择情况为 \(S\),这一列 \(1\sim i-1\) 行的星号选择情况为 \(T\),多米诺骨牌总数为 \(x\) 的容斥系数和。显然 \(O(2^{2n}n^2m^2)\) 会TLE。

注意到我们只需要知道前一列 \(i\sim n\) 行的星号选择情况,所以可以使用轮廓线优化。时间复杂度 \(O(2^nn^2m^2)\)

min-max容斥的时候不需要管 \(T\) 集合以外的元素的情况。这点很显然,但是我之前没理解透,看了好久那个dx的转移百思不得其解……

CO int N=6,M=101;
char a[N][M];
int dp[2][1<<N][2*N*M];

int main(){
	int n=read<int>(),m=read<int>();
	for(int i=0;i<n;++i) scanf("%s",a[i]);
	int sum=n*(m-1)+m*(n-1);
	int now=0,pre=1;
	dp[now][0][0]=mod-1;
	for(int j=0;j<m;++j)for(int i=0;i<n;++i){
		swap(now,pre),memset(dp[now],0,sizeof dp[now]);
		for(int s=0;s<1<<n;++s)
			for(int x=0;x<=sum;++x)if(dp[pre][s][x]){
				int t=s>>i&1?s^1<<i:s;
				cadd(dp[now][t][x],dp[pre][s][x]);
				if(a[i][j]=='.') continue;
				t|=1<<i;
				int dx=(i>0 and ~s>>(i-1)&1)+(j>0 and ~s>>i&1)+(i<n-1)+(j<m-1);
				cadd(dp[now][t][x+dx],mod-dp[pre][s][x]);
			}
	}
	int ans=0;
	for(int i=1;i<=sum;++i){
		int inv=fpow(i,mod-2);
		for(int s=0;s<1<<n;++s) cadd(ans,mul(dp[now][s][i],inv));
	}
	ans=mul(ans,sum);
	printf("%d\n",ans);
	return 0;
}

轮廓线DP常用优化办法:滚动数组。它的意义不仅在于卡空间,而且能方便转移。比如列数变化的时候。

posted on 2020-01-04 10:54  autoint  阅读(217)  评论(0编辑  收藏  举报

导航