20200916 SCOI模拟T3(轮廓线dp)

1 篇文章 0 订阅
1 篇文章 0 订阅

T3 P3290 [SCOI2016]围棋

思路:
补集转化后用kmp优化轮廓线dp,再滚动数组优化空间

代码:

#include <bits/stdc++.h>
using namespace std;

#define re register
#define LL long long
typedef unsigned int uint;
typedef unsigned long long ull;
#define pb push_back
#define mp make_pair

namespace IO {
char _buf[1 << 21], *_p1 = _buf, *_p2 = _buf;
#define ch()                                                                 \
  (_p1 == _p2 &&                                                             \
           (_p2 = (_p1 = _buf) + fread(_buf, 1, 1 << 21, stdin), _p1 == _p2) \
       ? EOF                                                                 \
       : *_p1++)
inline int in() {
  int s = 0, f = 1;
  char x = getchar();
  for (; x < '0' || x > '9'; x = getchar())
    if (x == '-') f = -1;
  for (; x >= '0' && x <= '9'; x = getchar()) s = (s * 10) + (x & 15);
  return f == 1 ? s : -s;
}
char buf_[1 << 21];
int p1_ = -1;
inline void flush() {
  fwrite(buf_, 1, p1_ + 1, stdout);
  p1_ = -1;
}
inline void pc(char x) {
  if (p1_ == (1 << 21) - 1) flush();
  buf_[++p1_] = x;
}
inline void out(int x) {
  char k[30];
  int pos = 0;
  if (!x) {
    pc('0');
    return;
  }
  if (x < 0) {
    pc('-');
    x = -x;
  }
  while (x) {
    k[++pos] = (x % 10) | 48;
    x /= 10;
  }
  for (int i = pos; i; i--) pc(k[i]);
  return;
}
inline void out(string x) {
  int k = x.size();
  for (int i = 0; i < k; i++) pc(x[i]);
}
}  // namespace IO
using namespace IO;

const int mod = 1e9 + 7;
int n, m, C, Q;
int all;
char s[2][13];
int fail[2][13], f[2][1 << 12][7][7];
char node[3] = {'W', 'B', 'X'};

inline int power(int s, int c) {
  int ans = 1;
  for (; c; s = 1ll * s * s % mod, c >>= 1)
    if (c & 1) ans = 1ll * ans * s % mod;
  return ans;
}

signed main() {
  n = in(), m = in(), C = in(), Q = in();
  all = power(3, n * m);
  while (Q--) {
    for (int t = 0; t < 2; t++) {
      scanf("%s", s[t] + 1);
      for (int i = 2, j = 0; i <= C; i++) {
        while (j && s[t][i] != s[t][j + 1]) j = fail[t][j];
        if (s[t][i] == s[t][j + 1]) j++;
        fail[t][i] = j;
      }
    }
    memset(f, 0, sizeof(f));
    f[0][0][0][0] = 1;
    int len = m - C + 1;
    int M = 1 << len;
    int now = 0;
    for (int i = 1; i <= n; i++) {
      for (int j = 1; j <= m; j++) {
        now ^= 1;
        memset(f[now], 0, sizeof(f[now]));
        for (int t = 0; t < M; t++) {
          for (int u = 0; u <= C; u++) {
            for (int v = 0; v <= C; v++) {
              if (f[now ^ 1][t][u][v]) {
                for (int x = 0; x <= 2; x++) {
                  int k0 = u;
                  while (k0 && (k0 == C || s[0][k0 + 1] != node[x]))
                    k0 = fail[0][k0];
                  if (s[0][k0 + 1] == node[x]) k0++;
                  int k1 = v;
                  while (k1 && (k1 == C || s[1][k1 + 1] != node[x]))
                    k1 = fail[1][k1];
                  if (s[1][k1 + 1] == node[x]) k1++;
                  if (j >= C && k1 == C && (t & 1)) continue;
                  int New = t;
                  if (j >= C) {
                    New >>= 1;
                    New |= (k0 == C) << (len - 1);
                  }
                  f[now][New][k0][k1] =
                      (f[now][New][k0][k1] + f[now ^ 1][t][u][v]) % mod;
                }
              }
            }
          }
        }
      }
      for (int t = 0; t < M; t++) {
        for (int j = 0; j <= C; j++) {
          for (int k = 0; k <= C; k++) {
            if (j || k) {
              f[now][t][0][0] = (f[now][t][0][0] + f[now][t][j][k]) % mod;
              f[now][t][j][k] = 0;
            }
          }
        }
      }
    }
    int ans = 0;
    for (int t = 0; t < M; t++) ans = (ans + f[now][t][0][0]) % mod;
    out(((all - ans) % mod + mod) % mod), pc('\n');
  }
  flush();
  return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值