HHKB Programming Contest 2020 E - Lamps(方案数)

在这里插入图片描述

题意:
. . .代表灯,
每个 . . . 可以点手电筒,照亮4个方向的 . . .(包括自己),直到遇到边界或者遇到 #。
对于所有的点灯方案,求出点亮灯的总数。

思路:
只需要对每个 . . .单独算贡献。
. . .的总数为 k k k
一个 . . . 点亮的方案数:若4个方向的所有 . . . 的数目为 m m m,则点亮的方案数为 ( 2 m − 1 ) ∗ ( 2 k − m ) (2^{m}-1)*(2^{k-m}) (2m1)(2km)

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <queue>
using namespace std;

typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn = 2e3 + 7;
const int mod = 1e9 + 7;

ll p[maxn * maxn];
char s[maxn][maxn];
int U[maxn][maxn],D[maxn][maxn],L[maxn][maxn],R[maxn][maxn];
int n,m;

void init() {
    
    
    p[0] = 1;
    for(int i = 1;i <= maxn * maxn - 2;i++) {
    
    
        p[i] = p[i - 1] * 2 % mod;
    }
    memset(U,0x3f,sizeof(U));
    for(int i = 1;i <= n;i++) {
    
    
        for(int j = 1;j <= m;j++) {
    
    
            if(s[i][j] == '.') {
    
    
                U[i][j] = i;
                U[i][j] = min(U[i][j],U[i - 1][j]);
            }
        }
    }
    
    for(int i = n;i >= 1;i--) {
    
    
        for(int j = 1;j <= m;j++) {
    
    
            if(s[i][j] == '.') {
    
    
                D[i][j] = i;
                D[i][j] = max(D[i][j],D[i + 1][j]);
            }
        }
    }
    
    memset(L,0x3f,sizeof(L));
    for(int j = 1;j <= m;j++) {
    
    
        for(int i = 1;i <= n;i++) {
    
    
            if(s[i][j] == '.') {
    
    
                L[i][j] = j;
                L[i][j] = min(L[i][j],L[i][j - 1]);
            }
        }
    }
    
    for(int j = m;j >= 1;j--) {
    
    
        for(int i = 1;i <= n;i++) {
    
    
            if(s[i][j] == '.') {
    
    
                R[i][j] = j;
                R[i][j] = max(R[i][j],R[i][j + 1]);
            }
        }
    }
}

int main() {
    
    
    scanf("%d%d",&n,&m);
    int cnt = 0;
    for(int i = 1;i <= n;i++) {
    
    
        scanf("%s",s[i] + 1);
        for(int j = 1;j <= m;j++) {
    
    
            if(s[i][j] == '.') {
    
    
                cnt++;
            }
        }
    }
    init();
    ll ans = 0;
    for(int i = 1;i <= n;i++) {
    
    
        for(int j = 1;j <= m;j++) {
    
    
            if(s[i][j] == '.') {
    
    
                int num = D[i][j] - U[i][j] + R[i][j] - L[i][j] + 1;
                ans = (ans + p[cnt - num] * (p[num] - 1) % mod + mod) % mod;
            }
        }
    }
    printf("%lld\n",((ans + mod) % mod));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/tomjobs/article/details/109017052