/* 返回顶部 */

POJ 3690 Constellations

gate

用时:60min,几乎全是照题解写的,所以没什么bug

题目大意:
给定一个\(N\times M\)的天空,\(T\)\(P*Q\)的星座,求有几个星座在天空中出现。
星空由 \('\ *\ '\)\('\ 0\ '\) 组成。
多组数据,\(1 \le N, M \le 1000, 1 \le T \le 100, 1 \le P, Q \le 50\)

二维哈希

把每一行、每一列当做一个字符串,用两个不同的模数分别哈希。
在枚举天空\((N\times M)\)矩阵时,用滚动哈希消去\(P\times Q\)范围以外的字符的影响

\(s[i][j]\)表示天空或星座的第\(i\)行第\(j\)列的字符。

先处理横向(先枚举\(i\),再枚举\(j\)):
\(g[i][j] = g[i][j-1]*Base1 + s[i][j]\ (j\in[1,Q])\\ g[i][j] = g[i][j-1]*Base1 + s[i][j]\ \ -\ \ s[i][j-Q]*(Base1)^Q\ (j\in[Q+1,M])\)

再处理竖向(先枚举\(j\),再枚举\(i\)):
\(j\)可以从\(Q\)开始枚举,因为只有大小为\(P*Q\)的矩阵是有用的。
\(f[i][j] = f[i-1][j]*Base2 + g[i][j]\ (i\in[i,P])\\ f[i][j] = f[i-1][j]*Base2 + g[i][j]\ \ -\ \ g[i-P][j]*(Base2)^P\ (i\in[P+1,N])\)

处理出每个\(P\times Q\)矩阵的哈希值后,
将每个星座的矩阵插入\(multiset\),再减去每个天空的矩阵。
最后\(T-mset.size()\)即为答案。

注意:

定义函数void cal(char s[][maxn])的时候,如果写成char s[][]
就会出现declaration of 's' as multidimensional array must have bounds for all dimensions except the first
这是因为,IDE只允许数组的第一维未给定。
所以在定义表示星座的变量char b的时候,
尽管根据范围只需要b[100][50][50],但为了传入cal函数,还是要写成b[100][50][maxn]

\(code\)

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<set>
#define MogeKo qwq
using namespace std;

#define ull unsigned long long

const int maxn = 1005;
const ull B1 = 19260817;
const ull B2 = 20031101;

char a[maxn][maxn],b[105][55][maxn]; //55

int n,m,t,p,q,ans;
ull f[maxn][maxn],g[maxn][maxn];
ull base1[maxn],base2[maxn];

void init(){
    base1[0] = base2[0] = 1;
    for(int i = 1;i <= 1000;i++){
        base1[i] = base1[i-1] * B1;
        base2[i] = base2[i-1] * B2;
    }
}

void cal(char s[][maxn],int n,int m){
    for(int i = 0;i < n;i++){
        g[i][0] = s[i][0];
        for(int j = 1;j < q;j++)
            g[i][j] = g[i][j-1]*B1 + s[i][j];
        for(int j = q;j < m;j++)
            g[i][j] = g[i][j-1]*B1 + s[i][j] - s[i][j-q]*base1[q];
    }
    for(int j = 0;j < m;j++){ //j = q-1
        f[0][j] = g[0][j];
        for(int i = 1;i < p;i++)
            f[i][j] = f[i-1][j]*B2 + g[i][j];
        for(int i = p;i < n;i++)
            f[i][j] = f[i-1][j]*B2 + g[i][j] - g[i-p][j]*base2[p];
    }       
}

void solve(){
    ans = 0;
    multiset <ull> star;
    for(int i = 1;i <= t;i++){
        cal(b[i],p,q);
        star.insert(f[p-1][q-1]);
    }
    cal(a,n,m);
    for(int i = p-1;i < n;i++)
        for(int j = q-1;j < m;j++)
            star.erase(f[i][j]);
    ans = t-star.size();
}


int main(){
    init();
    for(int id = 1;;id++){
        scanf("%d%d%d%d%d",&n,&m,&t,&p,&q);
        if(!(n|m|t|p|q)) break;
        for(int i = 0;i < n;i++)
            scanf("%s",a[i]);
        for(int i = 1;i <= t;i++)
            for(int j = 0;j < p;j++)
                scanf("%s",b[i][j]);
        solve();
        printf("Case %d: %d\n",id,ans);
    }
    return 0;
}
posted @ 2020-07-10 11:54  Mogeko  阅读(90)  评论(0编辑  收藏  举报