POJ 3690 Constellations(二进制压位+KMP)

题目链接

这儿~~


题解

这道题一看就知道是个二维hash,然而蒟蒻我并不会,于是想了另外一种水法:KMP

首先对小矩阵的每一列压位变成一个long long。然后小矩阵就变成了一个长度为q的数组。对大矩阵做同样的操作,每列p位压成一个数(可重叠),然后大矩阵就变成了n-p+1行m列的矩阵。

对矩阵的每一行与数组做KMP即可。

时间复杂度O(跑得过)。

ps:数据好水,刚AC的程序被我hack掉了。。


代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <cstdlib>
#define maxn 1010

using namespace std;

typedef long long LL;

int n, m, p, q, T, ans, Case;

char M1[maxn][maxn], M2[maxn][maxn];
LL D1[maxn][maxn], D2[maxn];
int nxt[maxn];

bool KMP(int x){

    nxt[0] = nxt[1] = 0;
    int k = 0;

    for(int i = 2; i <= q; i++){
        while(k && D2[k] != D2[i-1])  k = nxt[k];
        if(D2[k] == D2[i-1])  k ++;
        nxt[i] = k;
    }

    k = 0;

    for(int i = 1; i <= m; i++){
        while(k && D2[k] != D1[x][i-1])  k = nxt[k];
        if(D2[k] == D1[x][i-1])  k ++;
        if(k == q)  return true;
    }
    return false;
}

int main(){

    for(;;){
        scanf("%d%d%d%d%d", &n, &m, &T, &p, &q);

        if(!n && !m && !T && !p && !q)  break;

        ans = 0;

        for(int i = 1; i <= n; i++)
            scanf("%s", M1[i]);

        for(int j = 0; j < m; j++){
            D1[1][j] = 0LL;
            for(int i = 1, t = 0; i <= p; i++, t++)
                if(M1[i][j] == '*')  D1[1][j] += (1LL << t);

            for(int i = p+1; i <= n; i++){
                D1[i-p+1][j] = (D1[i-p][j] >> 1LL);
                if(M1[i][j] == '*')  D1[i-p+1][j] += (1LL << (p-1));
            }
        }

        while(T --){
            for(int i = 1; i <= p; i++)
                scanf("%s", M2[i]);

            for(int j = 0; j < q; j++){
                D2[j] = 0LL;
                for(int i = 1, t = 0; i <= p; i++, t++)
                    if(M2[i][j] == '*')  D2[j] += (1LL << t);
            }

            for(int i = 1; i <= n-p+1; i++)
                if(KMP(i)){  
                    ans ++;
                    break;
                }
        }

        printf("Case %d: %d\n", ++Case, ans);
    }

    return 0;
}

我对命运嗤之以鼻,命运赐我以葬礼。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值