CodeForces - 342D Xenia and Dominoes

博主的 BiBi 时间

感觉自己压行在向一种无法控制的方向发展。

Solution

先考虑不管 ‘O’ 该如何进行 D P \mathtt{DP} DP

竖着放的 D o m i n o \mathtt{Domino} Domino 是比较好搞的,关键是解决横着的。

f [ i ] [ j ] f[i][j] f[i][j] 为到第 i i i 列,之前的 D o m i n o \mathtt{Domino} Domino 已经全部合法,本列需要 i + 1 i+1 i+1 列来空位置的状态为 j j j(如 j = ( 101 ) 2 j=(101)_2 j=(101)2,就是 i + 1 i+1 i+1 列的第一,三个位置需要空着放横着的 D o m i n o \mathtt{Domino} Domino)。还需要预处理出 s t o [ i ] sto[i] sto[i] 表示 i i i 列的 ‘X’ 的状态。

然后枚举 i , j , k i,j,k i,j,k i , j i,j i,j 定义同上, k k k 就是枚举的 i − 1 i-1 i1 列的状态)。

我们考虑什么时候 k k k 能转移到 j j j

  • k k k 状态需要后一列来补的位置 j j j 状态没有障碍。
  • 除了 j j j 状态的 ‘X’ 位置与补的位置,剩下第 i i i 列的位置要么不放,要么放一个竖着的。

接下来我们考虑 ‘O’。发现可以把 ‘O’ 转化为 ‘X’,因为 ‘O’ 合法只要至少一个 D o m i n o \mathtt{Domino} Domino 短的边对着它,可以枚举 ‘O’ 旁边上下左右 D o m i n o \mathtt{Domino} Domino 这样对着它的情况( 4 4 4 种),不过这样会算重,容斥一下就好了。

Code

#include <cstdio>
#include <cstring>

#define rep(i, _l, _r) for(register signed i = (_l), _end = (_r); i <= _end; ++ i)
#define fep(i, _l, _r) for(register signed i = (_l), _end = (_r); i >= _end; -- i)
#define erep(i, u) for(signed i = head[u], v = to[i]; i; i = nxt[i], v = to[i])
#define print(x, y) write(x), putchar(y)

template <class T> inline T read(const T sample) {
	T x = 0; int f = 1; char s;
	while((s = getchar()) > '9' || s < '0') if(s == '-') f = -1;
	while(s >= '0' && s <= '9') x = (x << 1) + (x << 3) + (s ^ 48), s = getchar();
	return x * f;
}
template <class T> inline void write(const T x) {
	if(x < 0) return (void) (putchar('-'), write(-x));
	if(x > 9) write(x / 10);
	putchar(x % 10 ^ 48);
}
template <class T> inline T Max(const T x, const T y) {return x > y ? x : y;}
template <class T> inline T Min(const T x, const T y) {return x < y ? x : y;}
template <class T> inline T fab(const T x) {return x > 0 ? x : -x;}
template <class T> inline T Gcd(const T x, const T y) {return y ? Gcd(y, x % y) : x;}

const int N = 1e4 + 5, mod = 1e9 + 7;

char g[3][N];
int n, X, Y, dir[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}}, sto[N], f[N][10], l[10], r[10], ans;

bool ok(const int x, const int y) {
	if(x < 0 || x >= 3 || y < 0 || y >= n || g[x][y] == 'X') return 0;
	return 1;
}

int DP() {
	memset(sto, 0, sizeof sto);
	memset(f, 0, sizeof f);
	rep(i, 0, 2) rep(j, 0, n - 1)
		if(g[i][j] == 'X') sto[j] |= (1 << i);
	rep(i, 0, n - 1) {
		rep(j, 0, 7) {
			if(sto[i] & j) continue;
			rep(k, 0, 7) {
				int t = (j | k | sto[i]), tmp;
				if(i == 0) tmp = (k == 0);
				else tmp = f[i - 1][k];
				if((k & (sto[i] | j)) == 0 && (t == 1 || t == 4 || t == 7))
					f[i][j] = (f[i][j] + tmp) % mod;
			}
		}
	}
	return f[n - 1][0];
}

int main() {
	int cnt;
	n = read(9);
	rep(i, 0, 2) scanf("%s", g[i]);
	rep(i, 0, 2) rep(j, 0, n - 1)
		if(g[i][j] == 'O') {X = i, Y = j; g[i][j] = 'X'; break;}
	rep(i, 1, 15) {
		int tmp = i; cnt = 0;
		bool flag = 0;
		rep(j, 0, 3) {
			if(tmp & 1) {
				l[++ cnt] = dir[j][0], r[cnt] = dir[j][1];
				l[++ cnt] = (dir[j][0] << 1), r[cnt] = (dir[j][1] << 1);
			}
			tmp >>= 1;
		}
		rep(j, 1, cnt) if(! ok(X + l[j], Y + r[j])) {flag = 1; break;}
		if(flag) continue;
		rep(j, 1, cnt) g[X + l[j]][Y + r[j]] = 'X';
		if((cnt >> 1) & 1) ans = (ans + DP()) % mod;
		else ans = (ans - DP() + mod) % mod;
		rep(j, 1, cnt) g[X + l[j]][Y + r[j]] = '.';
	}
	print(ans, '\n');
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值