2018 nowcoder 多校第二场 K题 carpet

题意

找一个最小权值和 二维循环周期。

题解:

一般这种题,都先扔掉最优化的条件,思考如何求解,然后在考虑最优化。

那么如何求解二维循环周期(注意不是循环节)呢?显然对于每一行KMP一下就可以找到每一行的循环周期,对于一个size=p行*q列的周期,意味着column[i] = column[i+q],更具体的说就是 对于每一行r 都有s[r][i] = s[r][i+q] 。这意味着q是每一行的循环周期。那么思路就显然了。我们需要找到所有的n行公共的循环周期,所有m列公共的循环周期。然后进行任意的组合,就可以得到所有循环周期。

如何最优化:考虑任意一个非最小的循环周期(设为p*q):P*Q,有(P>=p&&Q>=q&&!(P==p&&Q==q)).我们知道p*q一定是P*Q的子矩形。。。因为分别可以用P*Q和p*q两种size生成整个矩阵,两个生成矩阵相等。。。所以是显然的。所以既然是子矩阵。。那么肯定选最小的那种阿。。问题变成了权值矩阵固定p*q大小子矩阵的最大值最小问题。

这个就不用二分了吧。。明明可以线性的。。用单调队列单独扫每一行,对于每一个位置(i,j)计算出

m a x V a l [ i ] [ j ] = max k = j j + q 1 a [ i ] [ k ]
然后在对每一列单独用单调队列扫,对于每一个个位置(i,j)计算出
a n s [ i ] [ i ] = max k = i i + p 1 m a x V a l [ k ] [ j ]
最后输出
min i = 1 n p + 1 min j = 1 m q + 1 a n s [ i ] [ j ]

“这不傻逼题吗?”

Code:

//
// Created by calabash_boy on 18-7-23.
//
#include<bits/stdc++.h>
//#define Debug(x) cerr<<#x<<" "<<x<<endl;
using namespace std;
const int maxn = 1e6+100;

struct KMP{
    int nxt[maxn];
    int len;
    void clear(){
        len =0;
        nxt[0] = nxt[1] =0;
    }
    /* 1-bas */
    /* 注意在ss结尾添加‘\0’ */
    void init(char* ss){
        len = strlen(ss+1);
        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]);
        }
    }
    void debug(){
        for (int i=0;i<=len;i++){
            printf("[debug] nxt[%d]=%d\n",i,nxt[i]);
//            Debug(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;
vector<vector<int> >maxVal;
int cnt1[maxn],cnt2[maxn];
int n,m;
char S[maxn];
pair<int,int> pq[maxn];int l,r;
int main(){
#ifdef ONLINE_JUDGE
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
#endif
    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=maxn;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;
}

猜你喜欢

转载自blog.csdn.net/calabash_boy/article/details/81180001
今日推荐