zoukankan      html  css  js  c++  java
  • 2019牛客暑期多校训练营(第八场)

    传送门

    A.All-one Matrices(单调栈)

    •题意

      给你一个只包含 0,1 的 n×m 的矩阵 s;

      求只由 1 组成的矩阵的个数,并且这些矩阵不存在包含关系;

    •题解

      定义 h[ i ][ j ] 表示 ( i , j ) 位置及其之上的连续的 1 的个数;

      那么,通过单调栈可以求出 ( i , j ) 位置的 l = L[ i ][ j ] 和 r = R[ i ][ j ];

      当前这个只包含 1 的矩阵是否包含于其他更大的矩阵呢?

      即如何判断当前这个矩阵对答案的贡献呢?

      只需要判断 i+1 行的 [ l , r ] 列是否含有 r-l+1 个 1 即可;

      如果 i+1 行的相应列含有 r-l+1 个 1,那么,由下一行的相同列组成的 1 矩阵势必要包含当前的矩阵;

      如果当前矩阵对答案有贡献,是不是就让 ans++ 呢?

      答案是否定的;

      因为如果 ( i , j ) 位置之前的位置 ( i , x )(x < j) 的高度 h[ i ][ x ] 与 h[ i ][ j ] 相等的;

      并且和 h[ i ][ j ] 所求的 1 矩阵相同,那么,当前这个矩阵就不能对答案有贡献;

      这个通过单调栈求出的信息判断一下就好了;

    •Code

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define INF 0x3f3f3f3f
      4 #define INFll 0x3f3f3f3f3f3f3f3f
      5 #define ll long long
      6 #define pii pair<int ,int >
      7 #define psi pair<string ,int >
      8 #define pb(x) push_back(x)
      9 #define ls(x) (x<<1)
     10 #define rs(x) (x<<1|1)
     11 #define GCD(a,b) __gcd(a,b)
     12 #define PI acos(-1)
     13 #define mem(a,b) memset(a,b,sizeof(a))
     14 #define endl '
    '
     15 #define isLeap(x) (x%4==0&&x%100!=0||x%400==0)
     16 #define Close() std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
     17 const int maxn=3e3+50;
     18 
     19 int n,m;
     20 char s[maxn][maxn];
     21 int h[maxn];
     22 int l[maxn];
     23 int r[maxn];
     24 int one[maxn];
     25 stack<int >sta;
     26 vector<int >v[maxn];
     27 
     28 void Clear()
     29 {
     30     while(!sta.empty())
     31         sta.pop();
     32 }
     33 void Work()
     34 {
     35     Clear();
     36     for(int i=1;i <= m;++i)
     37     {
     38         while(!sta.empty() && h[sta.top()] >= h[i])
     39             sta.pop();
     40 
     41         l[i]=sta.empty() ? 1:sta.top()+1;
     42         sta.push(i);
     43     }
     44     Clear();
     45     for(int i=m;i >= 1;--i)
     46     {
     47         while(!sta.empty() && h[sta.top()] >= h[i])
     48             sta.pop();
     49 
     50         r[i]=sta.empty() ? m:sta.top()-1;
     51         sta.push(i);
     52     }
     53 }
     54 ll Solve()
     55 {
     56     mem(h,0);
     57 
     58     ll ans=0;
     59     for(int i=1;i <= n;++i)
     60     {
     61         for(int j=1;j <= m;++j)
     62         {
     63             if(s[i][j] == '1')
     64                 h[j]++;
     65             else
     66                 h[j]=0;
     67         }
     68 
     69         Work();///单调栈
     70 
     71         mem(one,0);
     72         if(i != n)
     73         {
     74             for(int j=1;j <= m;++j)
     75                 one[j]=one[j-1]+(s[i+1][j] == '1');
     76         }
     77         for(int j=0;j <= n;++j)
     78             v[j].clear();
     79 
     80         for(int j=1;j <= m;++j)
     81         {
     82             int siz=v[h[j]].size();
     83             int cur=h[j];
     84             ///如果其前一个高度相同的位置与当前位置j的l[j],r[j]相同,那么当前位置无需计算
     85             if(cur == 0 || siz != 0 && l[v[cur][siz-1]] == l[j] && r[v[cur][siz-1]] == r[j])
     86                 continue;
     87 
     88             int x=l[j];
     89             int y=r[j];
     90             v[h[j]].push_back(j);
     91             
     92             if(one[y]-one[x-1] != y-x+1)
     93                 ans++;///如果i+1行的[x,y]列无y-x+1个1,那么ans++
     94         }
     95     }
     96     return ans;
     97 }
     98 int main()
     99 {
    100 //     freopen("C:\Users\hyacinthLJP\Desktop\in&&out\contest","r",stdin);
    101 //    freopen("C:\Users\hyacinthLJP\Desktop\in&&out\contest","w",stdout);
    102     scanf("%d%d",&n,&m);
    103     for(int i=1;i <= n;++i)
    104         scanf("%s",s[i]+1);
    105 
    106     printf("%lld
    ",Solve());
    107 
    108     return 0;
    109 }
    View Code

    B.Beauty Values(记录结果再利用的DP)

    •题意

      给你一个序列 a,求序列 a 的任意一个区间 [l,r] 中,元素不同的个数的加和;

    •题解

      定义 dp[ i ] 表示以 i 为结尾的所有区间所包含的元素不同的数的个数;

      即 $dp[i]=sum_{j=1}^{j <= i}f{j,i}$,$f{j,i}$指的是[ j , i ]区间不同数的个数;

      那么,对于 i 位置的数 ai

      ①i 位置为 ai 首次出现的位置:

        $dp[i]=dp[i-1]+i$;

      ②[1,i-1] 中 ai 出现的最晚的位置为 j:

        $dp[i]=dp[i-1]+i-j$;

    •Code

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define INF 0x3f3f3f3f
     4 #define INFll 0x3f3f3f3f3f3f3f3f
     5 #define ll long long
     6 #define pii pair<int ,int >
     7 #define psi pair<string ,int >
     8 #define pb(x) push_back(x)
     9 #define ls(x) (x<<1)
    10 #define rs(x) (x<<1|1)
    11 #define GCD(a,b) __gcd(a,b)
    12 #define PI acos(-1)
    13 #define mem(a,b) memset(a,b,sizeof(a))
    14 #define endl '
    '
    15 #define isLeap(x) (x%4==0&&x%100!=0||x%400==0)
    16 #define Close() std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    17 const int maxn=1e5+50;
    18 
    19 int n;
    20 int a[maxn];
    21 int p[maxn];
    22 ll dp[maxn];
    23 
    24 int main()
    25 {
    26 //    freopen("C:\Users\hyacinthLJP\Desktop\in&&out\contest","r",stdin);
    27 //    freopen("C:\Users\hyacinthLJP\Desktop\in&&out\contest","w",stdout);
    28     scanf("%d",&n);
    29 
    30     mem(dp,0);
    31     mem(p,0);
    32 
    33     for(int i=1;i <= n;++i)
    34         scanf("%d",a+i);
    35 
    36     for(int i=1;i <= n;++i)
    37     {
    38         dp[i]=dp[i-1]+i;
    39 
    40         dp[i] -= p[a[i]];
    41         p[a[i]]=i;
    42     }
    43 
    44 //    for(int i=1;i <= n;++i)
    45 //        printf("i=%d,dp=%lld
    ",i,dp[i]);
    46     ll ans=0;
    47     for(int i=1;i <= n;++i)
    48         ans += dp[i];
    49 
    50     printf("%lld
    ",ans);
    51 
    52     return 0;
    53 }
    View Code

    C.CDMA(构造)

    •题意

      假设序列 s,t 都只含有 n 个元素;

      定义 $scdot t=sum_{i=1}^{i<=n}s_icdot t_i$ ;

      构造一个 m×m 的矩阵 a,其中 m = 2k , 1 ≤k ≤ 10,使其满足:

      ①矩阵中只包含 -1,1;

      ②任意不同的两行 a[ i ],a[ j ], a[ i ]·a[ j ] = 0;

    •题解

      根据 m = 2 , m = 4 的满足条件的矩阵找规律;

      m = 2:

      $left( egin{array}{cc} 1 & 1 \ 1 & -1 end{array} ight)$

      m = 4:

      $left( egin{array}{cccc} 1 & 1 & 1 & 1 \ 1 & -1 & 1 & -1 \ 1 & 1 & -1 & -1 \ 1 & -1 & -1 & 1 \ end{array} ight)$

      看出啥了没?

      m = 4 时,从行,列的中间劈开,劈成 4 个 2×2 的子矩阵,你会发现,前三个子矩阵 = (m=2时的矩阵);

      最后一个子矩阵 = (m=2时的矩阵取反);

      根据上述规律,可以求出 m = 8,16,....,1024 时的满足条件的矩阵;

    •Code

     1 #include<bits/stdc++.h>
     2 #define mem(a,b) memset(a,b,sizeof(a))
     3 using namespace std;
     4 const int maxn=(1<<10)+50;
     5  
     6 int m;
     7 string base[maxn];
     8  
     9 int main()
    10 {
    11     base[0]="11";
    12     base[1]="10";///0表示-1
    13  
    14     for(int k=2;k <= 10;++k)
    15     {
    16         m=1<<k;
    17         for(int i=0;i < m/2;++i)
    18             base[i] += base[i];
    19  
    20         for(int i=m/2;i < m;++i)
    21         {
    22             base[i]=base[i%(m/2)];
    23             for(int j=m/2;j < m;++j)
    24                 base[i][j]=(base[i][j] == '0' ? '1':'0');
    25         }
    26     }
    27  
    28     int m;
    29     scanf("%d",&m);
    30     for(int i=0;i < m;++i)
    31         for(int j=0;j < m;++j)
    32             printf("%d%c",base[i][j] == '0' ? -1:1,j == m-1 ? '
    ':' ');
    33     return 0;
    34 }
    View Code

    G.Gemstones(模拟)

    •题意

      给你一个只包含大写字母的串 s;

      如果相邻的三个字符为相同的字母,那么,便可将这三个相同的字母消去;

      求最多可以消去多少次;

    •题解

      用 vector 模拟;

      每次加入一个新字符,判断他和 vector 中的后两个字符是否为相同字符,如果是,消去即可;

    •Code

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define INF 0x3f3f3f3f
     4 #define INFll 0x3f3f3f3f3f3f3f3f
     5 #define ll long long
     6 #define pii pair<int ,int >
     7 #define psi pair<string ,int >
     8 #define pb(x) push_back(x)
     9 #define ls(x) (x<<1)
    10 #define rs(x) (x<<1|1)
    11 #define GCD(a,b) __gcd(a,b)
    12 #define PI acos(-1)
    13 #define mem(a,b) memset(a,b,sizeof(a))
    14 #define endl '
    '
    15 #define isLeap(x) (x%4==0&&x%100!=0||x%400==0)
    16 #define Close() std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    17 const int maxn=1e5+50;
    18 
    19 char s[maxn];
    20 vector<char >p;
    21 
    22 int main()
    23 {
    24 //    freopen("C:\Users\hyacinthLJP\Desktop\in&&out\contest","r",stdin);
    25 //    freopen("C:\Users\hyacinthLJP\Desktop\in&&out\contest","w",stdout);
    26     scanf("%s",s+1);
    27 
    28     ll ans=0;
    29     int len=strlen(s+1);
    30     for(int i=1;i <= len;++i)
    31     {
    32         p.pb(s[i]);
    33 
    34         int n=p.size();
    35         if(n >= 3 && p[n-1] == p[n-2] && p[n-2] == p[n-3])
    36         {
    37             ans++;
    38             for(int j=1;j <= 3;++j)
    39                 p.erase(p.end()-1);
    40 
    41         }
    42     }
    43     printf("%lld
    ",ans);
    44 
    45     return 0;
    46 }
    View Code
  • 相关阅读:
    pyinstaller
    screen
    docker
    rsync
    shutil模块
    mysql innodb 理解
    B 树和B+树存储的区别
    B-树原理分析
    mysql 通过mycat 读写分离
    mysql 主从复制
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/11332669.html
Copyright © 2011-2022 走看看