题解
min-max 容斥 : min-max容斥介绍
或者看我的,虽然非常不详细
转化成求一个集合第一个被选的期望
因为覆盖的方案数只有2 * n * m - n - m
那么就想把覆盖方案数相同的方案放在一起DP
轮廓线DP,f[S][k]表示轮廓线状态为S,覆盖方案为k的方案数。注意这个DP转移的时候要带上min-max容斥的正负号。
知道k以后,期望就是:(2 * n * m - n - m) / k
总结:代码很好写。
一开始忽略了覆盖的方案数只有2 * n * m - n - m
一直没有想出怎么DP
代码很长的原因是前面的模板80行
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) ((x)&(-(x)))
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pr;
const ld inf = 2e18;
const int maxn = 100020;
const int mod = 998244353;
const int inv2 = (mod + 1) >> 1;
//NOTES: 任意乘法需要用mul,或者强制用long long。
//注意取模
//====================================basic operation===============================
inline void add(int &x, int y) {
x += y;
if (x >= mod) {
x -= mod;
}
}
inline void sub(int &x, int y) {
x -= y;
if (x < 0) {
x += mod;
}
}
inline int mul(int x, int y) {
return (int) ((long long) x * y % mod);
}
inline int power(int x, int y) {
int res = 1;
while (y) {
if (y & 1) {
res = mul(res, x);
}
x = mul(x, x);
y >>= 1;
}
return res;
}
inline int inv(int a) {
int b = mod, u = 0, v = 1;
while (a) {
int t = b / a;
b -= t * a;
swap(a, b);
u -= t * v;
swap(u, v);
}
if (u < 0) {
u += mod;
}
return u;
}
//=======================================================================================
int n,m,tot;
char ch[20][120];
int f[2][1 << 6][1300],now,last;
void solve(){
f[now][0][0] = mod - 1;
rep(i,1,m){
rep(j,1,n){
// cout<<" cehck: "<<i<<" "<<j<<" \n";
last = now , now ^= 1;
memset(f[now],0,sizeof(f[now]));
rep(k,0,(1 << n) - 1){
rep(l,0,tot){
if ( !f[last][k][l] ) continue;
int d = f[last][k][l];
// cout<<k<<" "<<l<<" "<<d<<endl;
int u = j && ((k >> (j - 2)) & 1) , lc = (k >> (j - 1)) & 1 , nS = k - (lc << (j - 1));
//not select
add(f[now][nS][l],d);
if ( ch[j][i] == '.' ) continue;
//select
int delta = 4 - (j == 1 || u) - (i == 1 || lc) - (j == n) - (i == m);
add(f[now][nS + (1 << (j - 1))][l + delta],mod - d);
}
}
}
}
// cout<<"tot : "<<tot<<endl;
int ans =0 ;
rep(k,0,(1 << n) - 1){
rep(l,1,tot){
int d = f[now][k][l];
// cout<<k<<" "<<l<<" "<<d<<endl;
add(ans,mul(d,mul(tot,inv(l))));
}
}
cout<<ans<<endl;
}
int main(){
cin>>n>>m;
rep(i,1,n) scanf("%s",ch[i] + 1);
tot = n * m * 2 - n - m;
solve();
}