[luogu P6275] [USACO20OPEN]Sprinklers 2: Return of the Alfalfa P

我丢 : https://www.luogu.com.cn/problem/P6275

显然DP,发现最后放出来肯定是长这个亚子

在这里插入图片描述

深色的一定要放,浅色的可放可不放,答案就是 2 浅色块数 \large 2^{\text{浅色块数}} 2浅色块数

把中间那条轮廓线抽出来

在这里插入图片描述

发现轮廓线折的地方一定要放,所以可以考虑DP轮廓线

f [ i ] [ j ] [ 0 / 1 ] f[i][j][0/1] f[i][j][0/1]表示当前轮廓线在第 i i i行,第 j j j列格子的右下角那个点,是横/竖的

考虑轮廓线长什么样,每次轮廓线只能向右或向下走一格,这就是个入门DP

因为每次转折的时候都有一个点是一定要放的,相当于随便放的减少了一个,就先把DP值除以 2 2 2在转移出去,最后乘上 2 s i z e \large 2^{size} 2size即可

code :

#include<bits/stdc++.h>
#define mod 1000000007
#define inv 500000004
#define int long long
#define N 2005
using namespace std;
int n, a[N][N], s[N][N], ss[N][N], f[N][N][2];
signed main() {
	scanf("%lld", &n);
	int cnt = 1;
	for(int i = 1; i <= n; i ++)
		for(int j = 1; j <= n; j ++) {
			char ch;
			scanf(" %c", &ch);
			if(ch == '.') a[i][j] = 1, cnt = cnt * 2 % mod;
		}
	f[0][1][0] = f[1][0][1] = cnt;
	for(int i = 0; i <= n; i ++)
		for(int j = 0; j <= n; j ++) {
			if(f[i][j][0]) {
				f[i][j + 1][0] += f[i][j][0], f[i][j + 1][0] %= mod;
				if(a[i + 1][j]) f[i + 1][j][1] += f[i][j][0] * inv % mod, f[i + 1][j][1] %= mod;
			}
			if(f[i][j][1]) {
				f[i + 1][j][1] += f[i][j][1], f[i + 1][j][1] %= mod;
				if(a[i][j + 1]) f[i][j + 1][0] += f[i][j][1] * inv % mod, f[i][j + 1][0] %= mod;
			}
		}
	printf("%lld", (f[n][n][0] + f[n][n][1]) % mod);
	return 0;
}

感觉是题解当中最容易理解的

posted @ 2020-05-16 08:54  lahlah  阅读(40)  评论(0编辑  收藏  举报