E carper kmp+滑动窗口 求二维矩阵的最小循环,并且令该循环区间的最大值最小

 链接:https://ac.nowcoder.com/acm/problem/16638
来源:牛客网

题目描述

White Cloud has a rectangle carpet of n∗mn*mnm. Grid(i,j)Grid (i,j)Grid(i,j) has a color colorA[i][j]colorA[i][j]colorA[i][j] and a cost costA[i][j]costA[i][j]costA[i][j].
White Rabbit will choose a subrectangle BBB of p∗qp*qpq from AAA and the color of each grid is colorB[0...p−1][0...q−1]colorB[0...p-1][0...q-1]colorB[0...p1][0...q1], the cost of BBB is the (maximum number in the corresponding subrectangle of costA∗(p+1)∗(q+1)costA*(p+1)*(q+1)costA(p+1)(q+1)).
Then colorBcolorBcolorB is continuously translated and copied in an infinite times, that is, expand colorBcolorBcolorB into an infinite new matrix, colorCcolorCcolorC, which satisfies colorC[i][j]=colorB[imodp][jmodq]colorC[i][j]=colorB[i mod p][j mod q]colorC[i][j]=colorB[imodp][jmodq].
White Rabbit must ensure that colorAcolorAcolorA is a subrectangle of colorCcolorCcolorC.
You need to find the minimum cost way.

输入描述:

The first line of input contains two integers n,m(0<n∗m≤1000000)n,m(0<n*m \leq 1000000)n,m(0<nm1000000)
For the next line of nnn lines, each line contains mmm lowercase English characters, denoting colorAcolorAcolorA.
For the next line of nnn lines, each line contains mmm integers in range [0,1000000000], denoting costAcostAcostA.

输出描述:

Print the minimum cost.
示例1

输入

复制
2 5
acaca
acaca
3 9 2 8 7
4 5 7 3 1

输出

复制
18

说明

choose subrectangle colorA[1...1][3...4]=ca, After copying unlimited copies
colorC=
cacacacaca ...
cacacacaca ...
cacacacaca ...
cacacacaca ...
cacacacaca ...
.........
colorA is a subrectangle of colorC
the cost is max(3,1)*(1+1)*(2+1).

分析:

求二维矩阵的最小循环,并且令该循环区间的最大值最小

kmp + 滑动窗口

最小循环:

分成横向和纵向

横向,求出每一行的周期,并求出所有行公共周期的最小周期

纵向同理

循环区间的最大值最小:

滑动窗口,将每一行的最小周期内的最大值

再根据每一行的最小周期内的最大值,求出每一列的最小周期内的最大值

对这些最大值取最小值即可

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
struct  KMP {
    int nxt[N],len;//表示和 i 位置相等的真前缀和真后缀的长度 
    char t[N];
    void clear() {
        len = nxt[0] = nxt[1] = 0;
    }
    /* 1-bas */
    /* 注意在ss结尾添加‘\0’ */
    void init(char* ss) {
        len = strlen(ss+1);
        memcpy(t,ss,(len+2)*sizeof(char));
        for(int i = 2;i<=len;i++) {
            nxt[i] = nxt[i-1];
            while(nxt[i] && ss[i] != ss[nxt[i] + 1]) nxt[i] = nxt[nxt[i]];
            nxt[i] += (ss[i] == ss[nxt[i]+1]);
        }
    }
    /* 求所有在ss串中的start_pos. 如果first_only设置为true,则只返回第一个位置*/
    vector<int> match(char *ss,bool first_only = false) {
        int len_s = strlen(ss+1);
        vector<int> start_pos(0);
        for(int i = 1,j = 1;i<=len_s;++i) {
            while(j!=1 && ss[i] != t[j]) j = nxt[j-1] + 1;
            if(ss[j] == t[j]) j ++ ;
            if(j == len + 1) {
                start_pos.push_back(i - len + 1);
                if(first_only) return start_pos;
                j = nxt[len] + 1;
            }
        } 
        return start_pos;
    }
    void debug() {
        for(int i = 0;i<=len;i++) {
            printf("[debug] nxt[%d]=%d\n",i,nxt[i]);
        }
    }
    /* 循环周期 形如 acaca 中 ac 是一个合法周期 */
    vector<int> periodic() {
        vector<int> ret;
        int now = len;
        while(now) {
            now = nxt[now];
            ret.push_back(len - now);
        }
        return ret;
    }
    /* 循环节 形如 acac 中ac、acac是循环节,aca不是*/
    vector<int> periodic_loop() {
        vector<int> ret;
        for(int x:periodic()) {
            if(len % x == 0) ret.push_back(x);
        }
        return ret;
    }
    int min_periodic_loop() {
        return periodic_loop()[0];
    }
}kmper;
vector<string> s;
vector<vector<int>> a,maxVal;
int cnt1[N],cnt2[N],n,m;
char S[N];
pair<int,int> pq[N];int l,r;

int main() {
    cin>>n>>m;
    s.resize(n+1);
    maxVal.resize(n+1);
    for(int i = 1;i<= n;i ++ ) {
        cin>>s[i];
    }
    a.resize(n+1);
    for(int i = 1;i<= n;i++ )  {
        a[i].resize(m+1);
        maxVal[i].resize(m+1);
        for(int j = 1;j<= m;j++) {
            cin>>a[i][j];
        }
    }
    int p,q;kmper.clear();
    for(int i = 1;i<=n;i++) {
        for(int j = 1;j<=m;j++) {
            S[j] = s[i][j-1];
        }
        S[m+1] = '\0';
        kmper.init(S);
        for(int x:kmper.periodic()) {
            cnt1[x] ++ ;
        }
    }    for (int j=1;j<=m;j++){
        for (int i=1;i<=n;i++){
            S[i] = s[i][j-1];
        }
        S[n+1]='\0';
        kmper.init(S);
        for (int x:kmper.periodic()){
            cnt2[x]++;
        }
    }
    for (int i=N;i>=1;i--){
        if (cnt1[i]==n){ q = i; }
        if (cnt2[i]==m){ p=i; }
    }
    for (int i=1;i<=n;i++){
        l = 0,r=0;
        for (int j=1;j<=m;j++){
            while (r>l&&pq[l].second<=j-q)l++;
            while (r>l&&pq[r-1].first<=a[i][j])r--;
            pq[r++] = {a[i][j],j};
            if (j>=q){
                maxVal[i][j-q+1] = pq[l].first;
            }
        }
    }
    int ans = 0x3f3f3f3f;
    for (int j=1;j<=m-q+1;j++){
        l=r=0;
        for (int i=1;i<=n;i++){
            while (r>l&&pq[l].second<=i-p)l++;
            while (r>l&&pq[r-1].first<=maxVal[i][j])r--;
            pq[r++] = {maxVal[i][j],i};
            if (i>=p){
                ans = min(ans,pq[l].first);
            }

        }
    }
    cout<<1LL*(p+1)*(q+1)*ans<<endl;
    return 0;
}

 

posted @ 2022-09-12 01:24  er007  阅读(140)  评论(0编辑  收藏  举报