UOJ422 【集训队作业2018】小Z的礼物
不难发现我们要求的是一个\(E(\max(S))\),这看起来比较困难,于是我们直接上min-max容斥,如果我们枚举了一个集合\(T\),集合\(T\)中有\(t\)对相邻格子,那么对答案的贡献就是\((-1)^{|T|+1}\frac{2nm-n-m}{t}\)
于是我们搞一个状压轮廓线的dp,设\(dp_{i,j,s,k}\)表示当前处理的格子是\((i,j)\),轮廓线状态为\(s\),选出了\(k\)对相邻格子,刷表转移即可
代码
#include<bits/stdc++.h>
#define re register
const int mod=998244353;
inline int dqm(int x) {return x<0?x+mod:x;}
inline int upd(int &x,int y) {x+=y;if(x>=mod)x-=mod;}
int dp[2][(1<<6)+1][1200],inv[1200],ans,n,m;
char ma[105][105];
int main() {
scanf("%d%d",&n,&m);int S=2*n*m-n-m,nS=0,len=(1<<n);--len;inv[1]=1;
for(re int i=2;i<=S;i++) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
for(re int i=1;i<=n;i++) scanf("%s",ma[i]+1);
dp[0][0][0]=mod-1;int o=0;
for(re int i=1;i<=m;i++)
for(re int j=1;j<=n;j++) {
memset(dp[o^1],0,sizeof(dp[o^1]));
for(re int s=0;s<=len;++s)
for(re int k=0;k<=nS;++k) {
if(!dp[o][s][k]) continue;
upd(dp[o^1][s&(len^(1<<(j-1)))][k],dp[o][s][k]);
if(ma[j][i]=='*') {
int det=0;
if(i>1&&!(s>>(j-1)&1)) det++;
if(j>1&&!(s>>(j-2)&1)) det++;
if(j<n) ++det;if(i<m) ++det;
upd(dp[o^1][s|(1<<(j-1))][k+det],dqm(mod-dp[o][s][k]));
if(k+det>nS) nS=k+det;
}
}
o^=1;
}
int ans=0;
for(re int s=0;s<=len;++s)
for(re int k=0;k<=S;++k) upd(ans,1ll*dp[o][s][k]*inv[k]%mod);
printf("%d\n",1ll*ans*S%mod);return 0;
}