传送门

本题要求本质不同的子矩阵,即位置不同也算相同(具体理解可以看样例自己yy)。

我们先看自己会什么,我们会求一个字符串中不同的子串的个数。我们考虑把子矩阵变成一个字符串。

先枚举矩阵的宽度,记为w(1<=w<=m)。再把一行之内的连续的w的字符用字符串hash哈成一个整数,再把这个整数hash成一个较小的数(相当于之前字符串的一个字符)。

把最后完成的矩阵在把没一列接起来,形成一个字符串(每列后要加一个字符如:1 2 3 4 2 3 3 5)。然后对这个串求我们会的子串个数(减去height值)即可。

#include <iostream>
#include <cstdio>
#include <map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll N = , M = ;
const ull P = ;
ll len, tot, ans;
ll n, m;
ll s[N * M], rnk[N * M], sa[N * M], sum[N * M], v1[N * M], v2[N * M], height[N * M];
char arr[N][M];
ull _hash[N][M];
map<ull, ll> mp;
bool cmp(ll *t, ll a, ll b, ll l) {
return t[a] == t[b] && t[a + l] == t[b + l];
}
void da() {
ll i, j, p = ;
for (i = ; i <= tot; i++) sum[i] = ;
for (i = ; i <= len; i++) sum[rnk[i] = s[i]]++;
for (i = ; i <= tot; i++) sum[i] += sum[i - ];
for (i = len; i >= ; i--) sa[sum[rnk[i]]--] = i;
for (j = ; j <= len; j *= , tot = p) {
for (p = , i = len - j + ; i <= len; i++) v2[++p] = i;
for (i = ; i <= len; i++) if (sa[i] > j) v2[++p] = sa[i] - j;
for (i = ; i <= len; i++) v1[i] = rnk[v2[i]];
for (i = ; i <= tot; i++) sum[i] = ;
for (i = ; i <= len; i++) sum[v1[i]]++;
for (i = ; i <= tot; i++) sum[i] += sum[i - ];
for (i = len; i >= ; i--) sa[sum[v1[i]]--] = v2[i];
for (swap(rnk, v2), rnk[sa[]] = , i = , p = ; i <= len; i++) {
rnk[sa[i]] = cmp(v2, sa[i - ], sa[i], j) ? p - : p++;
}
}
}
void calheight() {
ll i, j, p = ;
for (i = ; i <= len; i++) {
if (p) p--;
j = sa[rnk[i] - ];
while (s[i + p] == s[j + p]) p++;
height[rnk[i]] = p;
}
}
ull ksm[];
int main() {
ksm[] = ;
for (int i = ; i <= ; i++) {
ksm[i] = ksm[i - ] * P;
}
scanf("%lld%lld", &n, &m);
for (ll i = ; i <= n; i++) {
scanf("%s", arr[i] + );
for (ll j = ; j <= m; j++) {
_hash[i][j] = _hash[i][j - ] * P + arr[i][j] - 'A' + ;
}
}
for (ll w = ; w <= m; w++) {
tot = , len = ;
mp.clear();
for (ll j = ; j + w - <= m; j++) {
for (ll i = ; i <= n; i++) {
ull tmp = _hash[i][j + w - ] - _hash[i][j - ] * ksm[w];
if (mp[tmp] == ) {
mp[tmp] = ++tot;
}
s[++len] = mp[tmp];
}
s[++len] = ++tot;
}
da();
calheight();
ans += n * (n + ) / * (m - w + );
for (ll i = ; i <= len; i++) {
ans -= height[i];
}
}
cout << ans;
return ;
}

Samjia 和矩阵[loj6173](Hash+后缀数组)的更多相关文章

  1. liberOJ #6173. Samjia 和矩阵 hash+后缀数组

    #6173. Samjia 和矩阵 题目链接  : 点这里 题目描述 给你一个只包含大写字母的矩阵,求有多少本质不同的子矩阵. 输入格式 第一行包含两个整数 nnn , mmm ,表示矩阵 nnn 行 ...

  2. [USACO07DEC]Best Cow Line G 字符串hash || 后缀数组

    [USACO07DEC]Best Cow Line G [USACO07DEC]Best Cow Line G 小声哔哔:字符串hash牛逼 题意 给出一个字符串,每次可以从字符串的首尾取出一个字符, ...

  3. BZOJ 2119: 股市的预测 (Hash / 后缀数组 + st表)

    转博客大法好 自己画一画看一看,就会体会到这个设置关键点的强大之处了. CODE(sa) O(nlogn)→1436msO(nlogn)\to 1436msO(nlogn)→1436ms #inclu ...

  4. loj6173 Samjia和矩阵(后缀数组/后缀自动机)

    题目: https://loj.ac/problem/6173 分析: 考虑枚举宽度w,然后把宽度压位集中,将它们哈希 (这是w=2的时候) 然后可以写一下string=“ac#bc” 然后就是求这个 ...

  5. HDU-4622 Reincarnation 后缀数组 | Hash,维护和,扫描

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4622 题意:给一个字符串,询问某字串的不同字串的个数. 可以用后缀数组来解决,复杂度O(n).先求出倍 ...

  6. UVALive - 4513 Stammering Aliens ——(hash+二分 || 后缀数组加二分)

    题意:找一个出现了m次的最长子串,以及这时的最右的位置. hash的话代码还是比较好写的,,但是时间比SA多很多.. #include <stdio.h> #include <alg ...

  7. Uva12206 Stammering Aliens 后缀数组&&Hash

    Dr. Ellie Arroway has established contact with an extraterrestrial civilization. However, all effort ...

  8. Hash(LCP) || 后缀数组 LA 4513 Stammering Aliens

    题目传送门 题意:训练指南P225 分析:二分寻找长度,用hash值来比较长度为L的字串是否相等. #include <bits/stdc++.h> using namespace std ...

  9. acdream1116 Gao the string!(hash二分 or 后缀数组)

    问题套了一个斐波那契数,归根结底就是要求对于所有后缀s[i...n-1],所有前缀在其中出现的总次数.我一开始做的时候想了好久,后来看了别人的解法才恍然大悟.对于一个后缀来说 s[i...n-1]来说 ...

随机推荐

  1. 解决centos7命令无法补全

    背景 偶然发现本地虚拟机centos 7.7配置firewalld-cmd命令行无法补全,手敲命令太多,着实麻烦 解决方案 安装linux命令行补全工具,还能够补全命令参数 yum install b ...

  2. python2.7 安装 Scipy

    Numpy.scikit-learn可以直接 pip install xxx 但Scipy不能,在官网找到了安装方法: python -m pip install --user numpy scipy ...

  3. Ajax记载html

  4. 设计模式课程 设计模式精讲 3-4 依赖倒置原则讲解+coding

    1 课程讲解 1.1 定义 1.2 优点 1.3 细节描述 2 代码演练 2.0 代码展示优点 2.1 非面向接口编程 2.2 面向接口编程1 传参 2.3 面向接口编程2 构造函数 2.4 面向接口 ...

  5. ThinkPHP6源码分析之应用初始化

    ThinkPHP6 源码分析之应用初始化 官方群点击此处. App Construct 先来看看在 __construct 中做了什么,基本任何框架都会在这里做一些基本的操作,也就是从这里开始延伸出去 ...

  6. JAVA笔记---方法

    JAVA的方法 方法的基础 1. return 语句的一些高级应用 public class Method{ public static void main(Sting[] args){ System ...

  7. ZOJ4102 Array in the Pocket(2019浙江省赛)

    贪心~ #include<bits/stdc++.h> using namespace std; ; int a[maxn]; int b[maxn]; int vis[maxn]; se ...

  8. 10 JavaScript对象&类&for循环

    JavaScript对象 JavaScript中所有事物都是对象:字符串.数值.数组.函数.数学和正则表达式 JavaScript有些类型可以是字面量而非对象:如字符串.数值.布尔值 JavaScri ...

  9. spring cloud spring boot JPA 克隆对象修改属性后 无法正常的执行save方法进行保存或者更新

    2019-12-1220:34:58 spring cloud spring boot JPA 克隆对象修改属性后 无法正常的执行save方法进行保存或者更新 未解决

  10. IDEA下的SVN设置以及TortoiseSVN安装后bin目录下没有svn.exe如何解决?

    1.首先,我们要确保电脑上已经安装了TortoiseSVN. 2.打开IDEA-File-Settings-Version Control-Subversion,在右边的界面上选择TortoiseSv ...