首先这题题型很DP,然后容易想到DP状态f[i][j]为前i个人用前j种棋子的方案数。
后来感觉状态转移不太好写(本人太菜),就把第一维改成了四个人有无使用棋子的状态压缩,状态转移就很显然了。
这里我用的是刷表法:
f[k][j+1] += f[i][j], 当且仅当:
1. 在二进制下,i为k的真子集,且仅有一个数位不同(令该位置为p,则k=i|1<<p)。
2. s[p][j+1] = '1'。
f[i][j+1] += f[i][j], 正常的转移。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
const int MAXN = 5e3 + 5;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
#define For(i, a, b) for (int i = (int)(a); i <= (int)(b); i++)
#define Rep(i, a, b) for (int i = (int)(a); i >= (int)(b); i--)
#define DEBUG(x) cout << (x) << '\n'
#define fi first
#define se second

int n;
char a[4][MAXN];
ll f[20][MAXN];
inline void run() {
  cin >> n;
  For(i, 0, 3) cin >> a[i] + 1;
  f[0][0] = 1; //初始化
  For(j, 0, n) For(s, 0, 15) {
    For(i, 0, 3)
      if(!(s&1<<i) && a[i][j+1]&1) 
        f[s|1<<i][j+1] += f[s][j];   //第一种转移
    f[s][j+1] += f[s][j];            //第二种转移
  } 
  DEBUG(f[15][n]);                   //15的二进制为1111,表示四个人都用了棋子
}
int main() {
#ifdef Irene
  freopen("input.txt", "r", stdin);
  freopen("output.txt", "w", stdout);
#endif // Irene
  ios_base::sync_with_stdio(false);
  cin.tie(0), cin.tie(0);

  // int T; for(cin >> T; T--;)
  run(); return 0;
}