奶牛矩阵

奶牛矩阵

给出一个\(R\times C\)的字符矩阵,询问其最小的覆盖矩阵,定义一个覆盖矩阵为其不断的自我复制扩张以后原字符矩阵为其子矩阵,\(1≤R≤10000,1≤C≤75\)

从简单开始研究,刚开始不要研究二维,对于一行而言,我们发现一个结论,也就是它的覆盖矩阵,必然可以对齐左端,画张图自我理解,于是可以推广到二维中,必然可以对齐左上角。

此外从答案的角度来看,发现存在行列独立的性质,也就是对于一个子矩阵无限扩张,覆盖了原矩阵,我们可以把R行字符压成一行,接下来就变成一个字符串的子矩阵问题,同样可以对列进行处理,这样求出来的两个子矩阵长度的乘积就是我们的答案(感觉上模模糊糊是对的,很有道理,我也说不清)。

如何将多行压成一行,hash就可以了,于是接下来就变成一个字符串问题了,如何求一个字符串的"覆盖子串",我们需要寻找算法坐载体,字符串我们学过hash,kmp,trie,最小表示法,还有一些模型(如最长回文子串),不妨考虑kmp,然后发现一个性质,最小"覆盖子串"的长度也就是字符串长度-next[字符串长度],自我画图理解一下即可。

最后时间复杂度我们可以做到\(O(RC)\)

参考代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#define il inline
#define ri register
#define ll long long
#define ull unsigned ll
#define jzm 19260817
using namespace std;
char s[15000][100];
int Next[15000];
ull qz[15000],base[15000];
il int kmp(int);
il void get(char&);
int main(){
    int r,c,ans(1);base[0]=1;
    for(int i(1);i<=10000;++i)
        base[i]=base[i-1]*jzm;
    scanf("%d%d",&r,&c);
    for(int i(1),j;i<=r;++i)
        for(j=1;j<=c;++j)
            get(s[i][j]);
    for(int i(1),j;i<=r;++i)
        for(j=1;j<=c;++j)
            qz[i]=qz[i]*jzm+s[i][j];
    ans=kmp(r),memset(qz,0,sizeof(qz));
    for(int i(1),j;i<=c;++i)
        for(j=1;j<=r;++j)
            qz[i]=qz[i]*jzm+s[j][i];
    ans*=kmp(c),printf("%d",ans);
    return 0;
}
il int kmp(int n){
    for(int i(2),j(0);i<=n;++i){
        while(j&&qz[i]!=qz[j+1])j=Next[j];
        if(qz[i]==qz[j+1])++j;Next[i]=j;
    }return n-Next[n];
}
il void get(char &c){
    while(c=getchar(),c==' '||c=='\n'||c=='\r');
}

猜你喜欢

转载自www.cnblogs.com/a1b3c7d9/p/11257706.html