Codeforces Round #199 (Div. 2) D. Xenia and Dominoes

 

把 'O' 看成 'X',然后枚举它的四个方向看看是否能放,然后枚举 $2^4$ 种可能表示每种方向是否放了,放了的话就标成 'X',就相当于容斥,对于新的图去dp。

dp就是铺地砖,行用二进制来表示是否放了砖块。

#include <bits/stdc++.h>

const int MOD = 1e9 + 7;
const int N = 1e4 + 7;
const int dir[4][2] = {{0, -1}, {0, 1}, {1, 0}, {-1, 0}};
int dp[N][1 << 3], n, sx, sy;
char s[3][N];
int mp1[3][N], mp[3][N];

void M(int &a) {
    if (a >= MOD) a -= MOD;
    if (a < 0) a += MOD;
}

int get(int x) {
    int cnt = 0;
    while (x) {
        cnt++;
        x &= (x - 1);
    }
    return cnt;
}

int DP() {
    for (int i = 0; i < 8; i++)
        for (int j = 0; j <= n; j++)
            dp[j][i] = 0;
    dp[0][7] = 1;
    for (int i = 1; i <= n; i++) {
        int no = mp[0][i] + mp[1][i] * 2 + mp[2][i] * 4;
        for (int j = 0; j < 8; j++) {
            if (j & no) continue;
            dp[i][j | no] = dp[i - 1][7 - j];
            if (j == 3 || j == 6) {
                M(dp[i][j | no] += dp[i - 1][7]);
            }
            if (j == 7) {
                M(dp[i][j | no] += dp[i - 1][3]);
                M(dp[i][j | no] += dp[i - 1][6]);
            }
        }
    }
    return dp[n][7];
}

int main() {
    scanf("%d", &n);
    for (int i = 0; i < 3; i++) 
        scanf("%s", s[i] + 1);
    for (int i = 0; i < 3; i++)
        for (int j = 1; j <= n; j++)
            if (s[i][j] == 'O')
                sx = i, sy = j, mp1[i][j] = 1;
            else if (s[i][j] == 'X')
                mp1[i][j] = 1;
    std::vector<int> vec;
    for (int i = 0; i < 4; i++) {
        bool flag = 1;
        int x = sx + dir[i][0] * 2, y = sy + dir[i][1] * 2;
        if (x >= 0 && x < 3 && y >= 1 && y <= n) {
            for (int j = 1; j <= 2; j++) {
                if (mp1[sx + dir[i][0] * j][sy + dir[i][1] * j]) 
                    flag = 0;
            }
        } else {
            flag = 0;
        }
        if (flag)
            vec.push_back(i);
     }
     int S = 1 << vec.size();
     int ans = 0;
     for (int s0 = 1; s0 < S; s0++) {
         memcpy(mp, mp1, sizeof(mp));
         for (int j = 0; j < vec.size(); j++) {
             int i = vec[j];
             if (s0 >> j & 1) {
                 for (int k = 1; k <= 2; k++) {
                     int x = sx + dir[i][0] * k, y = sy + dir[i][1] * k;
                     mp[x][y] = 1;
                 }
             }
         }
         int f = get(s0) & 1 ? 1 : -1;
         M(ans += f * DP());
     }
     printf("%d\n", ans);
     return 0;
}
View Code

 

posted @ 2020-02-01 17:32  Mrzdtz220  阅读(109)  评论(0编辑  收藏  举报