Codeforces 1781H1 - Window Signals (easy version)

很套路的一道题,把 F1 写了,F2 感觉和 F1 gap 不太大就懒得写了/shui

首先需要明白大致思路:直接计算 \(2^{nm-k}-1\) 之所以会算重,是因为对于同一种图案,可能把它放在很多位置都是合法的。那么显然我们需要选一个代表元来把它的贡献唯一化,非常自然的想法就是把它固定在最左上角那个合法位置(即,取 \(x\) 最小那个,如果有多个取 \(y\) 最小的)。\(k\) 只有 \(2\),因此考虑从这个角度对 \(k\) 进行分类讨论。

首先 \(k=0\) 是 trivial 的,而因为没有坏掉的灯,所以必然可以把左上角固定在 \((1,1)\),所以这等价于第一行和第一列必须有亮着的点。容斥直接 \(O(1)\) 算即可。

\(k=1\) 的情况还是仿照 \(k=0\) 的情况。值得注意的一个点是,如果我们假设最左上角的合法点在 \((x,y)\),那么如果我们不知道这个图案的尺寸 \(h\times w\),我们就没法判断一个在 \((x,y)\) 前面的点 \((x',y')\) 不合法究竟是因为 \(x'>n-h+1\) 还是 \(y'>m-w+1\) 还是因为坏掉的那个点在矩形中而对应的图案中的点刚好是亮着的,因此考虑先枚举图案的尺寸,这样对于前面的所有点,给我们图案的限制是坏的那个位置在图案中对应的点必须是必亮点,而又因为图案尺寸限制的存在,必须强制钦定上下左右边界必须至少有一个亮着的点。这部分可以容斥,大概有 \(2^4\) 的常数,这样总复杂度 \(n^4·16\),但是注意到 \(h\) 的枚举是不必须的,因为如果 \((x,y)\) 满足下边界不超过 \(n\times m\) 矩阵的尺寸,那 \((x',y')\) 也超不过,这样复杂度少一个 \(n\),且常数降为 \(8\)

\(k=2\) 也类似,还是枚举 \(w\) 和第一个合法的点,对于前面的每个不合法点,如果两个坏掉的位置都在矩形内,给图案的限制是这两个位置至少有一个亮的点,如果只有一个在矩形内,限制则是这个位置必须是亮的。对于前者我们就在两点间连一条边,显然连出的是若干条链,直接在链上 DP 即可。

const int MAXN=40;
const int MOD=998244353;
int n,m,k,pw[MAXN*MAXN+5];
namespace ZERO{void solve(){printf("%d\n",(pw[n*m-1]+1ll*pw[(n-1)*(m-1)]*(pw[n-1]-1)%MOD*(pw[m-1]-1))%MOD);}}
namespace ONE{
	bool ban[MAXN+5][MAXN+5],mst[MAXN+5][MAXN+5];int x1,y1;
	void solve(){
		scanf("%d%d",&x1,&y1);int res=0;
		for(int w=1;w<=m;w++){
			memset(mst,0,sizeof(mst));
			for(int i=1;i<=n;i++)for(int j=1;j<=m-w+1;j++){
				for(int k=0;k<8;k++){
					memset(ban,0,sizeof(ban));
					if(x1>=i&&j<=y1&&y1<=j+w-1)ban[x1-i+1][y1-j+1]=1;
					for(int x=n-i+2;x<=n;x++)for(int y=1;y<=w;y++)ban[x][y]=1;
					if(k&1){for(int y=1;y<=w;y++)ban[1][y]=1;}
					if(k>>1&1){for(int x=1;x<=n-i+1;x++)ban[x][1]=1;}
					if(k>>2&1){for(int x=1;x<=n-i+1;x++)ban[x][w]=1;}
					int c=0,flg=0;
					for(int x=1;x<=n;x++)for(int y=1;y<=w;y++)
						c+=(!ban[x][y]&&!mst[x][y]),flg|=(ban[x][y]&&mst[x][y]);
					if(!flg){
						if(__builtin_parity(k))res=(res-pw[c]+MOD)%MOD;
						else res=(res+pw[c])%MOD;
					}
				}
				if(!(x1>=i&&j<=y1&&y1<=j+w-1))goto END;
				else mst[x1-i+1][y1-j+1]=1;
			}END:;
		}
		printf("%d\n",res);
	}
}
namespace TWO{
	bool ban[MAXN+5][MAXN+5],mst[MAXN+5][MAXN+5];int x1,y1,x2,y2;
	int hd[MAXN*MAXN+5],nxt[MAXN*MAXN*2+5],to[MAXN*MAXN*2+5],ec;
	void adde(int u,int v){
		to[++ec]=v;nxt[ec]=hd[u];hd[u]=ec;
		to[++ec]=u;nxt[ec]=hd[v];hd[v]=ec;
	}
	bool vis[MAXN*MAXN+5];
	int getid(int x,int y,int w){return (x-1)*w+y;}
	int len,a[MAXN*MAXN+5],dp[MAXN*MAXN+5][2];pii rid[MAXN*MAXN+5];
	void dfs(int id){
		vis[id]=1;pii pp=rid[id];
		if(ban[pp.fi][pp.se])a[++len]=0;
		else if(mst[pp.fi][pp.se])a[++len]=1;
		else a[++len]=-1;
		for(int e=hd[id];e;e=nxt[e])if(!vis[to[e]])dfs(to[e]);
	} 
	void solve(){
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);int res=0;
		for(int w=1;w<=m;w++){
			memset(mst,0,sizeof(mst));memset(hd,0,sizeof(hd));ec=0;
			for(int i=1;i<=n;i++)for(int j=1;j<=m-w+1;j++){
				bool flg1=(x1>=i&&j<=y1&&y1<=j+w-1);
				bool flg2=(x2>=i&&j<=y2&&y2<=j+w-1);
				for(int k=0;k<8;k++){
					memset(ban,0,sizeof(ban));
					if(flg1)ban[x1-i+1][y1-j+1]=1;
					if(flg2)ban[x2-i+1][y2-j+1]=1;
					for(int x=n-i+2;x<=n;x++)for(int y=1;y<=w;y++)ban[x][y]=1;
					if(k&1){for(int y=1;y<=w;y++)ban[1][y]=1;}
					if(k>>1&1){for(int x=1;x<=n-i+1;x++)ban[x][1]=1;}
					if(k>>2&1){for(int x=1;x<=n-i+1;x++)ban[x][w]=1;}
					int flg=0;
					for(int x=1;x<=n;x++)for(int y=1;y<=w;y++)
						flg|=(ban[x][y]&&mst[x][y]);
					if(!flg){
						memset(vis,0,sizeof(vis));
						for(int x=1;x<=n;x++)for(int y=1;y<=w;y++)
							rid[getid(x,y,w)]=mp(x,y);
						int prd=1;
						for(int x=1;x<=n;x++)for(int y=1;y<=w;y++){
							if(!vis[getid(x,y,w)]){
								len=0;dfs(getid(x,y,w));
								for(int t=0;t<=len;t++)dp[t][0]=dp[t][1]=0;
								for(int t=0;t<2;t++)if(a[1]!=(t^1))dp[1][t]=1;
								for(int t=2;t<=len;t++)for(int q=0;q<2;q++)if(a[t]!=(q^1))
									for(int r=0;r<2;r++)if(q||r)dp[t][q]=(dp[t][q]+dp[t-1][r])%MOD;
								int sum=0;
								for(int t=0;t<2;t++)sum=(sum+dp[len][t])%MOD;
								prd=1ll*prd*sum%MOD;
							}
						}
						if(__builtin_parity(k))res=(res-prd+MOD)%MOD;
						else res=(res+prd)%MOD;
					}
				}
				if(flg1&&flg2)adde(getid(x1-i+1,y1-j+1,w),getid(x2-i+1,y2-j+1,w));
				else if(flg1)mst[x1-i+1][y1-j+1]=1;
				else if(flg2)mst[x2-i+1][y2-j+1]=1;
				else goto END;
			}END:;
		}
		printf("%d\n",res);
	}
}
void solve(){
	scanf("%d%d%d",&n,&m,&k);
	if(!k)ZERO::solve();
	else if(k==1)ONE::solve();
	else TWO::solve();
}
int main(){
	for(int i=(pw[0]=1);i<=MAXN*MAXN;i++)pw[i]=pw[i-1]*2%MOD;
	int qu;scanf("%d",&qu);while(qu--)solve();return 0;
}
/*
4
2 2 1
1 1
2 2 1
1 2
2 2 1
2 1
2 2 1
2 2
*/
posted @ 2023-05-12 22:20  tzc_wk  阅读(69)  评论(2)    收藏  举报