zoukankan      html  css  js  c++  java
  • 牛客网多校第7场 J Sudoku Subrectangles 【构造】

    题目:戳这里

    题意:给一个n*m的矩阵,里面由a~z及A~Z构成,问有多少个子矩阵满足任意一行或一列中都没有相同的字母。

    解题思路:左上角和右下角两点可以确定一个矩阵。可以先预处理出来每个点作为一个矩阵的右下角,向左和向上的最长值。然后遍历每个点是右下角的情况,计算该点为右下角时,能构成多少个矩阵。计算方法为:

    1.设右下角为(i,j),它向左的最长值为r[i][j],向上最长之为c[i][j],设左上角为(x,y)。

    2.遍历j~j-r[i][j]+1,维护最小值minn[]。

    3.根据minn[]数组和c[][]数组,找到符合条件的左上角,计入答案。

    这三步操作的原因是,一个符合条件的左上角(x,y),要满足矩形底边上所有点的i-c[i][k]+1>=x,右边上所有点的j-r[k][j]+1>=y。

    代码思路比较绕,写的时候得静下心。

    附ac代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 #include <string>
     6 #include <cmath>
     7 #include <map>
     8 
     9 using namespace std;
    10 typedef long long ll;
    11 const int maxn = 1e3 + 10;
    12 char st[maxn][maxn];
    13 int r[maxn][maxn], c[maxn][maxn];
    14 int pos[maxn];
    15 int minn[maxn];
    16 const int inf = 0x3f3f3f3f;
    17 int main()
    18 {
    19     int n, m;
    20     scanf("%d %d", &n, &m);
    21     for(int i = 1; i <= n; ++i)
    22     {
    23         scanf("%s", st[i] + 1);
    24     }
    25     int len = 0;
    26     int cnt = 0;
    27     for(int i = 1; i <= n; ++i)
    28     {
    29         memset(pos, 0, sizeof(pos));
    30         for(int j = 1; j <= m; ++j)
    31         {
    32                 len = st[i][j] - 'A';
    33                 r[i][j] = j - pos[len];
    34                 r[i][j] = min(r[i][j], r[i][j - 1] + 1);//避免abba时,无法更新pos
    35                 pos[len] = j;
    36         }
    37     }
    38     for(int j = 1; j <= m; ++j)
    39     {
    40         memset(pos, 0, sizeof(pos));
    41         for(int i = 1; i <= n; ++i)
    42         {
    43                 len = st[i][j] - 'A';
    44                 c[i][j] = i - pos[len];
    45                 c[i][j] = min(c[i][j], c[i - 1][j] + 1);//同上
    46                 pos[len] = i;
    47         }
    48     }
    49     ll ans = 0;
    50     for(int i = 1; i <= n; ++i)
    51     {
    52         memset(minn, inf, sizeof(minn));
    53         for(int j = 1; j <= m; ++j)
    54         {
    55             for(int k = j; k >= j - r[i][j] + 1; --k)
    56                 minn[k] = min(minn[k + 1], c[i][k]);//(i,k)点能取到的最远列
    57 
    58             int len = j - r[i][j] + 1;
    59 
    60             for(int k = i; k >= i - c[i][j] + 1; --k)
    61             {
    62                 while(minn[len] < i - k + 1 || r[k][j] < j - len + 1)//倘若点(i,j)的minn值取不到k或(k,j)本身取不到minn,则说明len不符合条件
    63                 {
    64                     ++ len;
    65                     if(len > j) break;
    66                 }
    67                 if(len > j) break;
    68                 ans += j - len + 1;
    69                // printf("%lld ans
    ", ans);
    70             }
    71             //printf("%d ans
    ",ans);
    72         }
    73     }
    74     printf("%lld
    ", ans);
    75     return 0;
    76 }
    View Code
  • 相关阅读:
    每日总结2021.9.14
    jar包下载mvn
    每日总结EL表达语言 JSTL标签
    每日学习总结之数据中台概述
    Server Tomcat v9.0 Server at localhost failed to start
    Server Tomcat v9.0 Server at localhost failed to start(2)
    链表 java
    MVC 中用JS跳转窗体Window.Location.href
    Oracle 关键字
    MVC 配置路由 反复走控制其中的action (int?)
  • 原文地址:https://www.cnblogs.com/zmin/p/9556092.html
Copyright © 2011-2022 走看看