2021 CCPC训练 F. 地图压缩 ( kmp +字符Hash )

F. 地图压缩

在这里插入图片描述

样例

在这里插入图片描述

题意

给一个二维字符矩阵 , 每次询问给定一个区间 , 求这个区间的最小循环节。

思路

首先对于一维字符串的最小循环节(无需完全覆盖) , 方法就是求出kmp的nxt数组 , ans = len - nxt[len]
对于二维的情况 , 容易发现行与列之间是不冲突的 。
于是我们对行求一遍哈希 , 对列求一遍哈希 。
询问时把区间的每一行的哈希值取出来做一遍kmp的预处理 ,再把每一列的哈希值取出来做一遍kmp的预处理 , 两个结果相乘就是答案 。
这样处理的复杂度是 O(n*q) 的,满足题目要求 。

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2020;
int a[2020];
int solve(int n){      // kmp的预处理
    int pre[2020]= {0};
    memset(pre,0,sizeof pre);
    int j = 0;
    for(int i=2;i<=n;i++){
        while(j!=0&&a[i]!=a[j+1]) j = pre[j];
        if(a[i]==a[j+1]) j++;
        pre[i] = j;
    }
    return n - pre[n];
}
const int base = 27;
const int mod = 998244353;
int power[2020];
char mp[2020][2020];
int hash_r[2020][2020];
int hash_c[2020][2020];
signed main(){
    ios::sync_with_stdio(false);
    int n,q;
    cin>>n>>q;
    power[0] = 1;
    for(int i=1;i<2020;i++){
        power[i] = power[i-1]*base%mod;
    }
    for(int i=1;i<=n;i++){
        cin>>(mp[i]+1);
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            hash_r[i][j] = (hash_r[i][j-1]*base%mod+(mp[i][j]-'a'+1))%mod;  // 行哈希
            hash_c[i][j] = (hash_c[i-1][j]*base%mod+(mp[i][j]-'a'+1))%mod;   // 列哈希
        }
    }
    while(q--){
        int x1,y1,x2,y2;
        cin>>x1>>y1>>x2>>y2;
        int tot = 0;
        memset(a,0,sizeof a);
        // 求每一行的哈希值
        for(int i=x1;i<=x2;i++){
            a[++tot] = (hash_r[i][y2]-hash_r[i][y1-1]*power[y2-y1+1]%mod+mod)%mod;
        }
        int x = solve(tot);
        memset(a,0,sizeof a);
        tot = 0;
        // 求每一列的哈希值
        for(int i=y1;i<=y2;i++){
            a[++tot] = (hash_c[x2][i] - hash_c[x1-1][i]*power[x2-x1+1]%mod+mod)%mod;
        }
        int y = solve(tot);
        cout<<x*y<<endl;
    }
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值