专栏文章

题解:CF342D Xenia and Dominoes

CF342D题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mio8p79u
此快照首次捕获于
2025/12/02 15:11
3 个月前
此快照最后确认于
2025/12/02 15:11
3 个月前
查看原文
显然做法是计数 dp。
O 视作障碍,设 O 的坐标为 (x,y)(x,y),若 (x1,y),(x2,y)(x-1,y),(x-2,y) 均无障碍且没有出界则可以放置一个可滑动的多米诺,其他方向亦然。然后我们枚举哪些位置放这样的多米诺,等价于令这两个位置为障碍然后 dp 求答案即可。
但这样会算重,但只有四个方向,所以可以直接暴力容斥算。
再想如何 dp。注意到行数很少,且一个多米诺顶多管两列,我们考虑按列 dp。第 jj 列多米诺的放置情况取决于 j1j-1 列的放置情况,所以需要状态压缩记录第 jj 列的多米诺放置情况。
先考虑没有障碍的情况。设当前 dp 到第 jj 列。多米诺可以横着放,要求 (i,j1)(i,j-1) 对应的状态为未填 ;也可以竖着放,要求 (i1,j)(i-1,j) 为已填,因为多米诺只能管两列。一共 33 行,所以状态为 070 \sim 7,可以想到状态 ss 可以从前一列的 7s7-s 转移过来,对应的放置情况为全部横着放。若第 jj 列存在竖着放的情况,也就是状态为 3366 时,还可以从状态 77 转移过来;状态为 77 时还可以从状态 3,63,6 转移过来。
考虑存在障碍的情况。我们先算出第 jj 列的障碍情况 ss。如果 (i,j)(i,j) 存在障碍的话,我们在第 jj 列 dp 时要把这个位置当作没有放多米诺,因为 (i,j1)(i,j-1) 必须放;但是在第 j+1j+1 列 dp 时要把这个位置当作已经放了多米诺,因为这个位置不能填。然后枚举第 jj 列多米诺放置情况 kk,若 k&s>0k \& s>0 显然是不合法的。而对于下一列来说,其实际状态为 ksk \oplus s
所以有 fi,ks=fi1,7kf_{i,k \oplus s}=f_{i-1,7-k}。还有一些上述提到的特殊转移特判一下就可以了。
容斥是 242^4,状压是 232^3,因此复杂度是 O(Kn)O(Kn),其中 K=27K=2^7
代码:
CPP
#include<bits/stdc++.h>
using namespace std;
#define N 10005
#define M 10
#define int long long
const int mod = 1e9+7;
int n=3,m,i,j,ans,x,y,L,R,U,D,f[N][M];
char mp[M][N];
int dp(){
	memset(f,0,sizeof(f));
	f[0][7]=1;
	for(int i=1;i<=m;i++){
		int s=0;
		for(int j=1;j<=n;j++){
			if(mp[j][i]=='X') s^=(1<<(j-1));
		}
		for(int j=0;j<=7;j++){
			if(s&j) continue;
			int ns=(j^s);
			f[i][ns]=(f[i][ns]+f[i-1][7-j])%mod;
			if(j==3 || j==6) f[i][ns]=(f[i][ns]+f[i-1][7])%mod;
			if(j==7) f[i][ns]=(f[i][ns]+f[i-1][3]+f[i-1][6])%mod;
		}
	}
	return f[m][7];
}
signed main(){
	scanf("%lld",&m);
	for(i=1;i<=n;i++) scanf("%s",mp[i]+1);
	for(i=1;i<=n;i++){
		for(j=1;j<=m;j++) if(mp[i][j]=='O') x=i,y=j;
	}
	mp[x][y]='X';
	for(L=0;L<=1;L++){
		if(L && (y<3 || mp[x][y-1]=='X' || mp[x][y-2]=='X')) continue;
		for(R=0;R<=1;R++){
			if(R && (y>m-2 || mp[x][y+1]=='X' || mp[x][y+2]=='X')) continue;
			for(U=0;U<=1;U++){
				if(U && (x<3 || mp[x-1][y]=='X' || mp[x-2][y]=='X')) continue;
				for(D=0;D<=1;D++){
					if(D && (x>1 || mp[x][y+1]=='X' || mp[x][y+2]=='X')) continue;
					if(!L && !R && !U && !D) continue;					
					if(L) mp[x][y-1]='X',mp[x][y-2]='X';
					if(R) mp[x][y+1]='X',mp[x][y+2]='X';
					if(U) mp[x-1][y]='X',mp[x-2][y]='X';
					if(D) mp[x+1][y]='X',mp[x+2][y]='X';
					int res=dp();
					if((L+R+U+D)&1) ans=(ans+res)%mod;
					else ans=(ans-res+mod)%mod;
					if(L) mp[x][y-1]='.',mp[x][y-2]='.';
					if(R) mp[x][y+1]='.',mp[x][y+2]='.';
					if(U) mp[x-1][y]='.',mp[x-2][y]='.';
					if(D) mp[x+1][y]='.',mp[x+2][y]='.';
				}
			}
		}
	}
	printf("%lld\n",ans);
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...