原题解链接:https://ac.nowcoder.com/discuss/154293

dpi,j,kdp_{i,j,k}表示目前序列放入到第i i位,最后两个数字为j,k j,k时的方案数,提前将不合法的子段标记

转移方程为

dpi,k,l=j=149canj,k,l×dpi1,j,kd p_{i, k, l}=\sum_{j=1}^{49} \operatorname{can}_{j, k, l} \times d p_{i-1, j, k}

cancan00表示不合法,11表示合法。

时间复杂度 O(493n)O(49^3n)

#include <bits/stdc++.h>
using namespace std;
typedef long long lo;
const lo mo = 1e9 + 7;
lo lx, ly, lz, n, q, f[512][64][64], ans; bool can[64][64][64];
int main() {
  for (int i = 0; i < 50; ++i)
    for (int j = 0; j < 50; ++j)
      for (int k = 0; k < 50; ++k) can[i][j][k] = 1;
  scanf("%lld%lld", &n, &q);
  for (int i = 1; i <= q; i ++)
    scanf("%lld%lld%lld", &lx, &ly, &lz), can[lx][ly][lz] = can[lx][lz][ly] = can[ly][lx][lz] = can[ly][lz][lx] = can[lz][lx][ly] = can[lz][ly][lx] = 0;
  f[0][0][0] = 1;
  for (int i = 1; i <= n; i ++) {
    for (int j = 0; j < 50; j ++)
      for (int k = 0; k < 50; k ++)
        for (int l = 1; l < 50; l ++) f[i][k][l] = (f[i][k][l] + can[j][k][l] * f[i - 1][j][k]) % mo;
  }
  for (int i = 1; i < 50; i ++)
    for (int j = 1; j < 50; j ++) ans = (ans + f[n][i][j]) % mo;
  printf("%lld", ans);
  return 0;
}