gym101102D Rectangles (rmq+二分)

题意:

给你一个n*m(1e3)的矩阵,让你找出元素全部相同的子矩阵的个数。

思路:

可以预处理向左和向上的最大相同长度,然后对于每列用rmq维护一个区间最小值,

这个值表示向左延伸的长度,然后对于当前的元素,二分查找距离他最近的值小于他的上一个位置,

然后当前位置的贡献就是向左延伸的长度*纵坐标之差+1(这块矩阵完全相同,直接边长相乘)再加上上一个位置的贡献。

总复杂度就是n^2log(n)的

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <set>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int,int>pii;
const int N = 1e3+5;
const int mod = 1e9+7;
int T,n,m,a[N][N],u[N][N],l[N][N],t[N];
int dp[N][10],mm[N];
void initrmq(int x){
  for(int i=1;i<=n;++i)
    dp[i][0] = l[i][x];
  for(int j = 1;j<=mm[n];++j)
    for(int i=1;i+(1<<j)-1<=n;++i)
      dp[i][j] = min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
int rmq(int x,int y){
  int k = mm[y-x+1];
  return min(dp[x][k],dp[y-(1<<k)+1][k]);
}
int main(){
   scanf("%d",&T);
   while(T--){
     mm[0] = -1;
     scanf("%d%d",&n,&m);
     for(int i=1;i<=n;++i)
        mm[i] = ((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
     for(int i=1;i<=n;++i)
       for(int j=1;j<=m;++j)
          scanf("%d",&a[i][j]);
      for(int i=1;i<=n;++i){
         l[i][1] = 1;
         for(int j=2;j<=m;++j)
           if(a[i][j]==a[i][j-1])l[i][j] = l[i][j-1]+1;
           else l[i][j] = 1;
      }
      for(int j=1;j<=m;++j){
         u[1][j] = 1;
         for(int i=2;i<=n;++i){
            if(a[i][j]==a[i-1][j])u[i][j] = u[i-1][j]+1;
            else u[i][j] = 1;
         }
      }
      LL ret = 0;
      for(int j=1;j<=m;++j){
         t[1] = l[1][j];
         initrmq(j);
         for(int i=2;i<=n;++i){
            int x = i ,y = i-u[i][j]+1;
            int tmp = rmq(y,x);
            if(tmp>=l[i][j]){
              t[i] = l[i][j]*u[i][j];
              continue;
            }
            int ans;
            while(x>=y){
               int mid = x+y>>1;
               tmp = rmq(mid,i);
               if(tmp<l[i][j])y = mid+1;
               else ans = mid,x = mid-1;
            }
            t[i] = l[i][j]*(i-ans+1);
            if(i-u[i][j]+1<=ans-1)t[i]+=t[ans-1];
         }
         for(int i=1;i<=n;++i)ret+=t[i];
      }
      printf("%I64d\n",ret);
   }
   return 0;
}
时间: 2024-08-18 22:13:59

gym101102D Rectangles (rmq+二分)的相关文章

hdu 5289 Assignment(2015多校第一场第2题)RMQ+二分(或者multiset模拟过程)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5289 题意:给你n个数和k,求有多少的区间使得区间内部任意两个数的差值小于k,输出符合要求的区间个数 思路:求出区间的最大最小值,只要他们的差值小于k,那么这个区间就符合要求,但是由于n较大,用暴力一定超时,所以就要用别的方法了:而RMQ是可以求区间的最值的,而且预处理的复杂度只有O(nlogn),而查询只是O(1)处理,这样相对来说节约了时间,再根据右端点来二分枚举左端点(其实不用二分好像更快,估

HDU 5089 Assignment(rmq+二分 或 单调队列)

Assignment Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 557    Accepted Submission(s): 280 Problem Description Tom owns a company and he is the boss. There are n staffs which are numbered fr

BZOJ 题目3172: [Tjoi2013]单词(AC自动机||AC自动机+fail树||后缀数组暴力||后缀数组+RMQ+二分等五种姿势水过)

3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 1890  Solved: 877 [Submit][Status][Discuss] Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. Input 第一个一个整数N,表示有多少个单词,接下来N行每行一个单词.每个单词由小写字母组成,N<=200,单词长度不超过10^6

玲珑杯 Round 19 B Buildings (RMQ + 二分)

DESCRIPTION There are nn buildings lined up, and the height of the ii-th house is hihi. An inteval [l,r][l,r](l≤r)(l≤r) is harmonious if and only if max(hl,-,hr)?min(hl,-,hr)≤kmax(hl,-,hr)?min(hl,-,hr)≤k. Now you need to calculate the number of harmo

K-th occurrence(后缀树组+划分树+ST表+RMQ+二分)

2019CCPC网络选拔赛1003 HDU6704 题目大意: T个测试样例.一个长度为N的字符串S,之后Q个[l,r,k],表示一个子串S[l,r],求出第k个该子串的下标.起始坐标为1.不存在输出-1. 数据范围:1≤T≤20,  1≤N≤105,  1≤Q≤105,  1≤l≤r≤N,  1≤k≤N,  |S|=N; 赛后补题.参考题解说后缀树组+划分树+ST表+二分. 比赛的时候只会后缀树组不会划分树,赛后仔细想,觉得后缀数组可以,然而并不,会TLE. 补提的时候先是采用后缀树组+划分树

CodeForces 514D R2D2 and Droid Army RMQ+二分

题目链接:点击打开链接 题意:给定n m k 下面是n*m的矩阵 最多可以操作k次,每次操作可以使任意一列上所有的数 -= 1,( 0还是0) 要求得到连续最多的行数(每行里的整数都为0),输出任意一个方案(在每一列上操作的次数) 思路: 把每列单独考虑 枚举每行,二分找这行往下最多能清空的行数, RMQ维护一列的最大值. import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWr

hdu5289 RMQ+二分

RMQ预处理最大值,最小值,然后对于每一点,二分可能满足的区间长度,长度-1就是该店开始的区间满足的个数. #include<stdio.h> #include<string.h> #include<math.h> #define maxn 100010 #define LL __int64 int dp1[maxn][20],n,a[maxn],dp2[maxn][20]; int min(int x,int y) {return x<y?x:y;} int m

Codeforces #291 (Div. 2) D. R2D2 and Droid Army(RMQ+二分)

题意: 有n*m的矩阵,然后你有k发子弹.现在你可以朝着任意列发射子弹,每一发子弹都会使该列上的数值-1,最小减少到0. 现在问你连续最长的行数,在k发子弹内,使得这些行上的数值全部为0. 思路: 简单的二分枚举最长行数区间,每个区间的最大值决定了要发射的子弹数,所以是RMQ问题,当然这里的枚举全部枚举,用尺取法也可以. //889 ms #include<cstdio> #include<algorithm> #include<cstring> #include<

HDU 5726 GCD (RMQ + 二分)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5726 给你n个数,q个询问,每个询问问你有多少对l r的gcd(a[l] , ... , a[r]) 等于的gcd(a[l'] ,..., a[r']). 先用RMQ预处理gcd,dp[i][j] 表示从i开始2^j个数的gcd. 然后用map存取某个gcd所对应的l r的数量. 我们可以在询问前进行预处理,先枚举i,以i为左端点的gcd(a[i],..., a[r])的种类数不会超过log2(n)