[集训队作业2018]UOJ 422 小Z的礼物 - Min-Max容斥 - dp

题目大意:给你一个n*m的网格图,每个位置是0或者1,每次你可以选择一个1*2的子矩形涂黑。问期望多少次后所有1位置都被涂黑了?每次选择是独立的。 n 6 , m 100 n\le6,m\le100
题解:
考虑Min-Max容斥,问题转为对每个1的子集T求第一次覆盖到T中某个1的概率,这个就是总方案数分之有多少方案至少一端在T中,用类似轮廓线的方法dp这个即可。(一开始写了直接状压的做法,代码附在后面)

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define mod 998244353
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
	int x,ch;while((ch=gc)<'0'||ch>'9');
	x=ch^'0';while((ch=gc)>='0'&&ch<='9')
		x=(x<<1)+(x<<3)+(ch^'0');return x;
}
const int N=10,M=110;
char str[N][M];
inline int fast_pow(int x,int k,int ans=1) { for(;k;k>>=1,x=(lint)x*x%mod) (k&1)?ans=(lint)ans*x%mod:0;return ans; }
inline int upd(int &x,int y) { return x+=y,(x>=mod?x-=mod:0); }
inline int sol(int x,int z) { return (z&1)?(x?mod-x:0):x; }
namespace subtask345{
	const int N=8,MXS=70,M=110;
	int dp[2][N][MXS][M*N*2][2],inv[N*M*2],up[M][N];
	inline int acceptable_solution(int n,int m)
	{
		int all=(1<<n)-1,tot=2*m*n-m-n;
		rep(i,1,m)
		{
			up[i][0]=up[i-1][n];
			rep(j,1,n)
			{
				up[i][j]=up[i][j-1];
				if(j>1&&(str[j][i]=='*'||str[j-1][i]=='*')) up[i][j]++;
				if(i>1&&(str[j][i]=='*'||str[j][i-1]=='*')) up[i][j]++;
			//	debug(i)sp,debug(j)sp,debug(up[i][j])ln;
			}
		}
		dp[1][0][0][0][0]=1;
		rep(i,1,m)
		{
			#define now dp[i&1]
			#define nxt dp[(i+1)&1]
			rep(j,1,n) rep(s,0,all) rep(k,0,up[i][j]) rep(t,0,1) now[j][s][k][t]=0;
			rep(j,0,n-1) rep(s,0,all) rep(k,0,up[i][j]) rep(t,0,1) if(now[j][s][k][t])
			{
				upd(now[j+1][s^(s&(1<<j))][k+((s>>j)&1)+(j?((s>>(j-1))&1):0)][t],now[j][s][k][t]);
				if(str[j+1][i]=='*') upd(now[j+1][s|(1<<j)][k+(i>1)+(j>0)][t^1],now[j][s][k][t]);
			}
			rep(s,0,all) rep(k,0,up[i][n]) rep(t,0,1) nxt[0][s][k][t]=now[n][s][k][t];
			#undef now
			#undef nxt
		}
		#define now dp[m&1]
		int ans=0;rep(c,1,up[m][n]) inv[c]=fast_pow(c,mod-2);
		rep(s,0,all) rep(c,1,up[m][n]) rep(t,0,1)
			if(now[n][s][c][t]) upd(ans,sol((lint)inv[c]*now[n][s][c][t]%mod,t^1));
		return !printf("%lld\n",(lint)ans*tot%mod);
		#undef now
	}
}
int main()
{
	int n=inn(),m=inn();rep(i,1,n) scanf("%s",str[i]+1);
	return subtask345::acceptable_solution(n,m);return 0;
}
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define mod 998244353
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
	int x,ch;while((ch=gc)<'0'||ch>'9');
	x=ch^'0';while((ch=gc)>='0'&&ch<='9')
		x=(x<<1)+(x<<3)+(ch^'0');return x;
}
const int N=10,M=110;
char str[N][M];
inline int fast_pow(int x,int k,int ans=1) { for(;k;k>>=1,x=(lint)x*x%mod) (k&1)?ans=(lint)ans*x%mod:0;return ans; }
inline int upd(int &x,int y) { return x+=y,(x>=mod?x-=mod:0); }
inline int sol(int x,int z) { return (z&1)?(x?mod-x:0):x; }
namespace subtask345{
	const int N=8,MXS=70,M=110;
	int dp[M][MXS][2*N*M][2],sz[MXS],ok[M][MXS],calc[M][MXS];
	int inv[2*N*M];
	inline int acceptable_solution(int n,int m)
	{
		int all=(1<<n)-1,tot=2*n*m-n-m;
		rep(i,1,all) sz[i]=sz[i>>1]+(i&1);
		rep(i,1,m)
		{
			int t=0;
			rep(j,1,n) if(str[j][i]=='*') t|=(1<<(j-1));
			rep(s,0,all) if((s&t)==s)
			{
				ok[i][s]=1;
				rep(j,1,n-1) if(((s>>(j-1))&1)||((s>>j)&1)) calc[i][s]++;
			}
		}
		dp[0][0][0][0]=1;
		rep(i,0,m-1)
		{
			#define now dp[i]
			#define nxt dp[i+1]
			rep(s,0,all) rep(j,0,2*(i+1)*n-i-1-n) rep(k,0,1) nxt[s][j][k]=0;
			int up=(i?2*i*n-i-n:0);
			rep(s,0,all) rep(j,0,up) rep(k,0,1)
				if(now[s][j][k]) rep(t,0,all) if(ok[i+1][t])
				{
					int nj=j+(i?sz[s|t]:0)+calc[i+1][t],nk=k^(sz[t]&1);
					upd(nxt[t][nj][nk],now[s][j][k]);
				}
			#undef now
			#undef nxt
		}
		#define now dp[m]
		int ans=0;rep(i,1,tot) inv[i]=fast_pow(i,mod-2);
		rep(s,0,all) rep(c,1,tot) rep(k,0,1) if(now[s][c][k])
			upd(ans,sol((lint)inv[c]*now[s][c][k]%mod,k^1));
		ans=(lint)ans*tot%mod;return !printf("%d\n",ans);
		#undef now
	}
}
int main()
{
	int n=inn(),m=inn();rep(i,1,n) scanf("%s",str[i]+1);
	return subtask345::acceptable_solution(n,m);return 0;
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/87930950