zoukankan      html  css  js  c++  java
  • Samjia 和矩阵 LOJ #6173

    【题目描述】
    给你一个只包含大写字母的矩阵,求有多少本质不同的子矩阵。

    【输入格式】
    第一行包含两个整数 (n) , (m) ,表示矩阵 (n)(m) 列 。
    接下来 (n) 行描述这个矩阵。

    【输出格式】
    只含一个整数,为本质不同的子矩阵个数。

    题干简练.png

    ( ext{*********************})
    ( ext{*****题干简练*********})
    ( ext{*********************})
    ( ext{*********************})
    ( ext{********考完爆零******})
    ( ext{*********************})
    ( ext{*********************})
    ( ext{*********************})

    先枚举长度(l),然后将每个串压位哈希(哈希提前处理好就行)
    盗用一张图

    然后从上到下,从左到右,生成一个这样的串:ac$bc

    对于每个长度(l)生成的新串 将这个新串的本质不同的子串个数累加到答案上
    可以感性理解一下 枚举(l)就相当是枚举子矩阵的长度

    多简单鸭

    离散化写起来极其恶臭 迫不得已用了map(因为懒)
    大家不要学我 离散化大法好

    p.s. 模数998244353被卡到只有20分。。。要不用1e9+7要不用ull吧

    【代码】

    #include <bits/stdc++.h>
    #define mul 1000000007ull
    #define N 1000005
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    
    int n, m;
    ull hsh[205][205], p[205];
    char s[205][205];
    int now;
    ull t[20005], len, ans;
    int sa[N], sa2[N], rnk[N], sum[N], key[N], height[N];
    map<ull, int> mp;
    
    inline bool check(int *num, int x, int y, int l) {
    	return num[x] == num[y] && num[x+l] == num[y+l];
    }
    
    inline void suffix(int n, int m) {
    	int i, j, p; int *_rnk = rnk, *_sa2 = sa2;
    	for (i = 1; i <= m; i++) sum[i] = 0;
    	for (i = 1; i <= n; i++) sum[_rnk[i]=t[i]]++;
    	for (i = 2; i <= m; i++) sum[i] += sum[i-1];
    	for (i = n; i >= 1; i--) sa[sum[_rnk[i]]--] = i;
    	for (j = 1; j <= n; j <<= 1, m = p) {
    		for (p = 0, i = n - j + 1; i <= n; i++) _sa2[++p] = i;
    		for (i = 1; i <= n; i++) if (sa[i] > j) _sa2[++p] = sa[i] - j;
    		for (i = 1; i <= n; i++) key[i] = _rnk[_sa2[i]];
    		for (i = 1; i <= m; i++) sum[i] = 0;
    		for (i = 1; i <= n; i++) sum[key[i]]++;
    		for (i = 2; i <= m; i++) sum[i] += sum[i-1];
    		for (i = n; i >= 1; i--) sa[sum[key[i]]--] = _sa2[i];
    		for (swap(_rnk, _sa2), i = 2, p = 2, _rnk[sa[1]] = 1; i <= n; i++) {
    			_rnk[sa[i]] = check(_sa2, sa[i-1], sa[i], j) ? p-1 : p++;
    		}
    	} 
    	p = 0;
    	for (i = 1; i <= n; i++) rnk[sa[i]] = i;
    	for (i = 1; i <= n; i++) {
    		if (p) p--; j = sa[rnk[i]-1];
    		while (t[i+p] == t[j+p]) p++;
    		height[rnk[i]] = p; 
    	}
    }
    
    
    int main() {
    	scanf("%d %d", &n, &m);
    	for (int i = 1; i <= n; i++) scanf("%s", s[i]+1);
    	for (int i = 1; i <= n; i++) {
    		for (int j = 1; j <= m; j++) {
    			hsh[i][j] = (hsh[i][j-1] * mul + s[i][j]-'A'+1);
    		}
    	}
    	p[0] = 1;
    	for (int i = 1; i <= 200; i++) {
    		p[i] = p[i-1] * mul;
    	}
    	for (int l = 1; l <= m; l++) {
    		len = 0; now = 0; mp.clear();
    		for (int j = 1; j <= m - l + 1; j++) {
    			for (int i = 1; i <= n; i++) {
    				ull x = hsh[i][j+l-1] - hsh[i][j-1] * p[l];
    				if (!mp[x]) mp[x] = ++now;
    				t[++len] = mp[x];
    			}
    			t[++len] = ++now; 
    		}
    		now += 10;
    		suffix(len, now); 
    		ans += n * (n+1) / 2 * (m - l + 1);
    		for (int i = 1; i <= len; i++) {
    			ans -= height[i];
    		}
    	}
    	printf("%lld
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    2019.1.1-11 总结
    配置文件的选择
    2019.1.1-5 总结
    shell 脚本
    2017- 感谢自己
    debug和release版本的区别
    linux 下一些命令
    Python中getopt()函数的使用
    开发环境的一些基本认识
    Leetcode 49. Group Anagrams
  • 原文地址:https://www.cnblogs.com/ak-dream/p/AK_DREAM33.html
Copyright © 2011-2022 走看看