Matrix Matcher(字符串哈希||AC自动机)

题目
法一:字符串哈希,注意一下进制数取大一点;用getchar()+%c读入的时候会超时,用%s就不会,我在想%c是不是很慢。。

//#include<bits/stdc++.h>
#include<queue>
#include <cmath>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
#define mod (1000000007)
#define middle (l+r)>>1
#define lowbit(x) (x&(-x))
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int inf_max = 0x3f3f3f3f;
const ll Linf = 9e18;
const int maxn = 1e3 + 10;
const int maxm = 5e4 + 10;
const long double E = 2.7182818;
const double eps=0.0001;
using namespace std;
inline int read()
{
    int f=1,res=0;
    char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { res=res*10+ch-'0' ; ch=getchar(); }
    return f*res;
}
const ull base = 1000000007;
ull _hash[maxn][maxn],n,m,x,y,needhash,pre[maxn][maxn];
char ch[maxn][maxn],tar[maxn][maxn];
ull fpower(ull b,ull p) {
    ull res = 1;
    while(p) {
        if(p & 1) res = res * b;
        b = b * b;
        p >>= 1;
    }
    return res;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--) {
        needhash = 0;
        scanf("%d%d",&n,&m);
        for(int i = 1;i <= n; ++i) {
            scanf("%s",ch[i] + 1);
            for(int j = m;j >= 1; --j) {
                _hash[i][j] = _hash[i][j+1] * base + (ull)ch[i][j];
            }
        }
        scanf("%d%d",&x,&y);
        for(int i = 1;i <= x; i++) {
            scanf("%s",tar[i] + 1);
        }
        for(int i = x;i >= 1; --i)
            for(int j = y;j >= 1;--j)
                needhash = needhash * base + (ull)tar[i][j];
        x--;y--;
        int ans = 0;
        //pre[i][j] 第i列从第n行到第j行代表的值
        for(int j = 1;j + y <= m; ++j) {  //第j 列为起点
            for(int i = n;i >= 1; --i) { //第i行为起点
                pre[j][i] = pre[j][i + 1] * fpower(base,y + 1) + _hash[i][j] - _hash[i][j + y + 1] * fpower(base,y + 1);
            }
        }
        for(int i = 1;i + x <= n;++i) {
            for(int j = 1;j + y <= m; ++j) {
                ull tt = pre[j][i] - pre[j][i + x + 1] * fpower(base,(x+1) * (y+1));
                if(tt == needhash) ans++;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

法二:AC自动机,把第二个矩阵每一行作为一个模式串建立自动机,然后用第一个矩阵的每一行去匹配,如果匹配成功了某个串,就把这个串对应的左上角的行匹配次数++,然后遍历整个原矩阵,如果某个点的行匹配次数为x,那么答案就++;

//#include<bits/stdc++.h>
#include<queue>
#include <cmath>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
#define mod (1000000007)
#define middle (l+r)>>1
#define lowbit(x) (x&(-x))
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int inf_max = 0x3f3f3f3f;
const ll Linf = 9e18;
const int maxn = 1e3 + 10;
const int maxm = 100 + 10;
const long double E = 2.7182818;
const double eps=0.0001;
using namespace std;
inline int read()
{
    int f=1,res=0;
    char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { res=res*10+ch-'0' ; ch=getchar(); }
    return f*res;
}
const int N = 30;
int n,m,x,y,match[maxn][maxn];
char s1[maxn][maxn];
struct AC {
    int root,cnt,tree[maxm*maxm][N],fail[maxm*maxm*N],q[maxm*maxm*N],last[maxm*maxm*N];
    vector<int>row[maxm*maxm*N];
    int f,r;
    int getnewnode() {
        for(int i = 0;i < N; ++i) {
            tree[cnt][i] = 0;
        }
        fail[cnt] = last[cnt] = 0;row[cnt].clear();
        cnt++;
        return cnt - 1;
    }
    void Initial() {
        cnt = 0;
        root = getnewnode();
        f = r = 0;
    }
    void Insert(char *s,int r) {
        int now = root,l = strlen(s + 1);
        for(int i = 1;i <= l; ++i) {
            int id = s[i] - 'a';
            if(!tree[now][id]) tree[now][id] = getnewnode();
            now = tree[now][id];
        }
        row[now].push_back(r);
    }
    void getfail() {
        for(int i = 0;i < N; ++i) {
            if(tree[0][i]) {
                q[r++] = tree[0][i];
                fail[tree[0][i]] = 0;
                last[tree[0][i]] = (row[fail[tree[0][i]]].size() ? fail[tree[0][i]] : last[fail[tree[0][i]]]);
            }
        }
        while(f != r) {
            int u = q[f++];
            for(int i = 0;i < N; ++i) {
                if(tree[u][i]) {
                    fail[tree[u][i]] = tree[fail[u]][i];
                    q[r++] = tree[u][i];
                }else tree[u][i] = tree[fail[u]][i];
                last[tree[u][i]] = (row[fail[tree[u][i]]].size() ? fail[tree[u][i]] : last[fail[tree[u][i]]]);
            }
        }
    }
    void query(char *s,int r) {
        int now = root,l = strlen(s + 1);
        for(int i = 1;i <= l; ++i) {
            now = tree[now][s[i] - 'a'];
            int tmp = now,ind = 0;
            while(tmp != root) {
                for(int j = 0;j < row[tmp].size();++j) {
                    if(row[tmp][j]) {
                        if(r- row[now][j] + 1 > n) continue;
                        if(r- row[now][j] + 1 < 1) continue;
                        if(i- y + 1 > m) continue;
                        if(i- y + 1 < 1) continue;
                        match[r - row[now][j] + 1][i- y + 1]++;
                    }
                }
                tmp = last[tmp];
            }
        }
    }
}ACauto;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--) {
        memset(match,0,sizeof(match));
        ACauto.Initial();
        scanf("%d%d",&n,&m);
        for(int i = 1;i <= n; ++i) {
            scanf("%s",s1[i] + 1);
        }
        scanf("%d%d",&x,&y);
        for(int i = 1;i <= x; ++i) {
            scanf("%s",s1[0] + 1);
            ACauto.Insert(s1[0],i);
        }
        ACauto.getfail();
        for(int i = 1;i <= n; ++i) {
            ACauto.query(s1[i],i);
        }
        int ans = 0;
        for(int i = 1;i <= n; ++i)
            for(int j = 1;j <= m; ++j)
                if(match[i][j] == x) ans++;
        cout<<ans<<endl;
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值