传送门

本题要求本质不同的子矩阵,即位置不同也算相同(具体理解可以看样例自己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. 【PAT甲级】1043 Is It a Binary Search Tree (25 分)(判断是否为BST的先序遍历并输出后序遍历)

    题意: 输入一个正整数N(<=1000),接下来输入N个点的序号.如果刚才输入的序列是一颗二叉搜索树或它的镜像(中心翻转180°)的先序遍历,那么输出YES并输出它的后序遍历,否则输出NO. t ...

  2. 弱密码检测JR!

    1.JR(Joth the Ripper)简介·一款密码分析工具,支持字典式的暴力破解·通过对 shadow 文件的口令分析,可以检测密码·官方网站:http://www.openwall.com/j ...

  3. 「JSOI2011」分特产

    「JSOI2011」分特产 传送门 计数题. 考虑容斥掉每人至少一个的限制. 就直接枚举至少有多少人没有分到特产,然后剩下的随便分. \[Ans = \sum_{i = 0}^n (-1)^i {n ...

  4. mysql查询最大值,最小值,平均值,总和

    select max(score) maxScore,min(score) minScore,avg(score) avgScore,sum(score) sumScore from exam_sco ...

  5. Python磁力获取器命令行工具 torrent-cli

    作为一个搞代码的,找资源这种事肯定不能像普通人一样打开百度盲目查找,你需要写个爬虫工具来帮你完成这件事情啦! 兼容环境 Windows/Linux/MacOs 安装 pip 安装 $ pip inst ...

  6. java 8时间使用LocalDateTime,ZonedDateTime,LocalDate

    前言 java 8的时间已经能够满足日常的使用,也方便理解.joda-time作为一个有优秀的时间组件也不得不告知使用者在java 8以后使用自带的时间 LocalDateTime以及ZonedDat ...

  7. Linux 修改/etc/profile 出错 导致所有命令都 command not found 的解决办法

    执行命令 export PATH=/usr/bin:/usr/sbin:/bin:/sbin:/usr/X11R6/bin 然后再修改/etc/profile 再执行文件: source /etc/p ...

  8. android原始sqlite中query的复杂用法

    android直接执行sql是execSQL(String sql). 这个方法可以执行任意sql语句.但是改变这个不够灵活. query这个方法可以很好的解决这个问题. 执行query查询指定的数据 ...

  9. 分支预测(branch prediction)

    记录一个在StackOverflow上看到一个十分有趣的问题:问题. 高票答案的优化方法: 首先找到罪魁祸首: if (data[c] >= 128) sum += data[c]; 优化方案使 ...

  10. Electron调用C++的DLL

    1. 安装ffi-napi npm install ffi-napi   2. c++ dll 注意,若electron是X64的,则dll也应为X64,同理32位. myAddDll是c++的dll ...