USACO20OPEN Sprinklers 2: Return of the Alfalfa 【动态规划】

因为两种不同的洒水器的方向是反的且同一块地不能被两种洒水器覆盖,我们可以发现我们可以画出一个类似分割线的东西,左边的全是一种花,右边的是另一种,同时我们还发现在这个分割线上,拐角位置必须放洒水机,其他的地方随便放就行了,然后就可以dp了

dp[i][j][0/1]表示当我们把分割线画到(i, j)时,且最近的一笔是横着的(0)或竖着的(1),此时的答案数,每当到了一拐角时,答案数就要除2因为这一个位置必须放洒水机

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define gi get_int()
#define int long long
const int MAXN = 3000, MOD = 1e9 + 7, INV = 5e8 + 4;
int get_int()
{
  int x = 0, y = 1;
  char ch = getchar();
  while (!isdigit(ch) && ch != '-')
    ch = getchar();
  if (ch == '-')
    y = -1, ch = getchar();
  while (isdigit(ch))
    x = x * 10 + ch - '0', ch = getchar();
  return x * y;
}

int map[MAXN][MAXN], dp[MAXN][MAXN][2];

signed main()
{
  freopen("code.in", "r", stdin);
  freopen("code.out", "w", stdout);

  int n = gi, cnt = 1;
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= n; j++) {
      char ch = getchar();
      if (ch == '.')
        map[i][j] = 1, (cnt *= 2) %= MOD;
    }
    getchar();
  }
  dp[1][0][1] = dp[0][1][0] = cnt;
  for (int i = 0; i <= n; i++)
    for (int j = 0; j <= n; j++) {
      if (dp[i][j][0] != 0) {
        (dp[i][j + 1][0] += dp[i][j][0]) %= MOD;
        if (map[i + 1][j] == 1)
          (dp[i + 1][j][1] += dp[i][j][0] * INV % MOD) %= MOD;
      }
      if (dp[i][j][1] != 0) {
        (dp[i + 1][j][1] += dp[i][j][1]) %= MOD;
        if (map[i][j + 1] == 1)
          (dp[i][j + 1][0] += dp[i][j][1] * INV % MOD) %= MOD;
      }
    }
  std::cout << (dp[n][n][1] + dp[n][n][0]) % MOD;

  return 0;
}
posted @ 2021-05-21 15:49  enisp  阅读(53)  评论(0)    收藏  举报