奶牛矩阵

Posted a1b3c7d9

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了奶牛矩阵相关的知识,希望对你有一定的参考价值。

奶牛矩阵

给出一个\(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');

以上是关于奶牛矩阵的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 1706: [usaco2007 Nov]relays 奶牛接力跑矩阵乘法+Floyd

Floyd矩阵乘法BZOJ1706- [usaco2007 Nov]relays 奶牛接力跑

relays 奶牛接力跑(矩阵快速幂求最短路径)

JZYZOJ1355 [usaco2007]奶牛赛跑 矩阵乘法 离散化

Fliptile奶牛踩瓷砖 (状态压缩,开关问题,枚举)

bzoj1706/usaco2007 Novrelays 奶牛接力跑——矩阵快速幂/倍增floyd