• 牛客网暑期ACM多校训练营(第二场)carpet


    传送门:carpet

    题意

    有一个n*m的地毯,aij表示地毯每格的元素,bij表示地毯每格的价格,要求选取一块价格最大值最小的地毯,并且这块地毯无限铺开之后,原地毯是其子矩阵。

    题解

    先找到这个矩阵的最小循环节子矩阵,求一下每行的循环节长度用map记录,取出现次数为m并且循环节长度最小的;每列也求一下循环节长度用map记录,取出现次数为m并且循环节长度最小的;这样就得到了最小的循环节子矩阵。然后问题就变成了求一个p*q的子矩阵最大值的最小值,可以参考这个题 Fake Maxpooling (求得是k*k子矩阵的最大值的和)稍加修改变成求p*q子矩阵的最大值的最小值就好了。这里用到单调队列,先横着算一下每个长度为p的区间的最大值记录下来,然后再把记录下来的数组竖着同样算一下长度为q的区间,将每次求到的最大值取最小值。
     
    ps:谨记像这种横着求一遍竖着求一遍的一定不能求第二遍的时候直接copy第一遍的代码改,会把自己坑死的!!!不要手懒!!!

    代码

      1 #include<bits/stdc++.h>
      2 #define ll long long
      3 using namespace std;
      4   
      5 const int maxn=1e6+10;
      6 int nt1[maxn];
      7 int nt2[maxn];
      8 string s[maxn];
      9 unordered_map<int,int> mp;
     10 deque<int> dq;
     11 int val[maxn],v[maxn];
     12   
     13 void getnt1(string s)
     14 {
     15     int i=0,j=-1;
     16     nt1[0]=-1;
     17     while(i<s.size()){
     18         if(j==-1||s[i]==s[j]) i++,j++,nt1[i]=j;
     19         else j=nt1[j];
     20     }
     21 }
     22   
     23 void getnt2(string s)
     24 {
     25     int i=0,j=-1;
     26     nt2[0]=-1;
     27     while(i<s.size()){
     28         if(j==-1||s[i]==s[j]) i++,j++,nt2[i]=j;
     29         else j=nt2[j];
     30     }
     31 }
     32   
     33 int main()
     34 {
     35     ios::sync_with_stdio(false);
     36     cin.tie(0);
     37     cout.tie(0);
     38   
     39     int n,m;
     40     cin>>n>>m;
     41     for(int i=0;i<n;i++) cin>>s[i];
     42     for(int i=0;i<n;i++){
     43         for(int j=0;j<m;j++){
     44             cin>>v[i*m+j];
     45         }
     46     }
     47   
     48     int pp=m,qq=n;
     49     for(int i=0;i<n;i++){
     50         getnt1(s[i]);
     51         int p=nt1[m];
     52         while(p!=-1){
     53             mp[m-p]++;
     54             if(mp[m-p]==n) pp=min(pp,m-p);
     55             p=nt1[p];
     56         }
     57     }
     58     mp.clear();
     59     for(int i=0;i<m;i++){
     60         string t;
     61         for(int j=0;j<n;j++){
     62             t+=s[j][i];
     63         }
     64         getnt2(t);
     65         int p=nt2[n];
     66         while(p!=-1){
     67             mp[n-p]++;
     68             if(mp[n-p]==m) qq=min(qq,n-p);
     69             p=nt2[p];
     70         }
     71     }
     72   
     73     int ans=1e9;
     74     for(int i=0;i<n;i++){
     75         while(dq.size()) dq.pop_back();
     76         for(int j=0;j<pp-1;j++){
     77             while(dq.size()&&v[i*m+dq.back()]<=v[i*m+j]) dq.pop_back();
     78             dq.push_back(j);
     79         }
     80         for(int j=pp-1;j<m;j++){
     81             while(dq.size()&&dq.front()+pp<=j) dq.pop_front();
     82             while(dq.size()&&v[i*m+dq.back()]<=v[i*m+j]) dq.pop_back();
     83             dq.push_back(j);
     84             val[i*m+j]=v[i*m+dq.front()];
     85         }
     86     }
     87     for(int i=pp-1;i<m;i++){
     88         while(dq.size()) dq.pop_back();
     89         for(int j=0;j<qq-1;j++){
     90             while(dq.size()&&val[dq.back()*m+i]<=val[j*m+i]) dq.pop_back();
     91             dq.push_back(j);
     92         }
     93         for(int j=qq-1;j<n;j++){
     94             while(dq.size()&&dq.front()+qq<=j) dq.pop_front();
     95             while(dq.size()&&val[dq.back()*m+i]<=val[j*m+i]) dq.pop_back();
     96             dq.push_back(j);
     97             ans=min(ans,val[dq.front()*m+i]);
     98         }
     99     }
    100     ll res=(ll)ans*(ll)(pp+1)*(ll)(qq+1);
    101     cout<<res<<endl;
    102     return 0;
    103 }
  • 相关阅读:
    MySQL server version for the right syntax to use near ‘USING BTREE
    随笔
    [python]自问自答:python -m参数?
    [linux]查看linux下端口占用
    [linux]scp指令
    [编程题目]泥塑课
    How can I learn to program?
    [python]在场景中理解装饰器
    [前端]分享一个Bootstrap可视化布局的网站
    [python]python元类
  • 原文地址:https://www.cnblogs.com/lilibuxiangtle/p/13395111.html
Copyright © 2020-2023  润新知