1. 程式人生 > >Luogu P1191 矩形【題解】

Luogu P1191 矩形【題解】

題目描述

給出一個 n × n n \times n 的矩陣,矩陣中,有些格子被染成白色,有些格子被染成黑色,現要求矩陣中白色矩形的數量。

輸入輸出格式

輸入格式:

第一行,一個整數 n

n ,表示矩形的大小。

接下來 n n 行,每行 n n 個字元,這些字元為“ W

W ”或“ B B ”。其中“ W W ”表示白格,“ B
B
”表示黑格。

輸出格式:

一個正整數,為白色矩形數量

輸入輸出樣例

輸入樣例#1:

4
WWBW
BBWB
WBWW
WBWB

輸出樣例#1: 複製

15

說明

對於 30 % 30\% 的資料, n 50 n ≤ 50

對於 100 % 100\% 的資料, n 150 n ≤ 150


洛谷上這個題其實是可以 n 4 n^4 過的,直接列舉就行,這裡講一下 n 3 n^3 做法。

首先處理一下每行的高度,就是 h h 陣列,然後迴圈判斷連續個數,累加即可。

//參考_Atyou大神程式碼
#include<iostream>
#include<cstdio>
#include<ctype.h>
using namespace std;
inline int read(){
    int x=0,f=0;char ch=getchar();
    while(!isdigit(ch))f|=ch=='-',ch=getchar();
    while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
    return f?-x:x;
}
char c[157][157];
int n,h[157],ans;
int main() {
	int n=read();
    for(int i=1;i<=n;i++)scanf("%s",c[i]+1);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++)//掃一遍
            if(c[i][j]!='B')h[j]++;//判斷每行連續的白色個數
            else h[j]=0;//因為只統計白色高度,所以如果遇到黑色就清零
        for(int j=1;j<=n;++j){
        	int high=h[j];  
            for(int k=j;k<=n;++k){
                if(!h[k])break;
                high=min(high,h[k]);//連續個數取min
                ans+=high;//矩形個數=連續個數
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}
又:考試考到這個題的強化版, n 2000 n≤2000 ,留坑待填。

回來填坑:

用單調棧維護每個區間內的最大值,出棧時

寫一份考試題的程式碼:
#include<iostream>
#include<cstdio>
#include<ctype.h>
using namespace std;
inline int read(){
    int x=0,f=0;char ch=getchar();
    while(!isdigit(ch))f|=ch=='-',ch=getchar();
    while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
    return f?-x:x;
}
char c[2007][2007];
int up[2007][2007],L[2007],R[2007];
int s[2007];
long long ans;
int main() {
    int n=read(),m=read();
    for(int i=1;i<=n;++i)scanf("%s",c[i]+1);
    for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)
        if(c[i][j]=='.')up[i][j]=up[i-1][j]+1;
    for(int i=1;i<=n;i++){
        int top=0;s[0]=0;
        for(int j=1;j<=m;j++){
            while(top && up[i][j]<=up[i][s[top]])--top;
            L[j]=s[top]+1;s[++top]=j;
        }
        top=0;s[0]=m+1;
        for(int j=m;j>=1;--j){
            while(top && up[i][j]<up[i][s[top]])--top;
            R[j]=top?s[top]-1:m;s[++top]=j;
        }
        for(int j=1;j<=m;++j){
            long long l=j-L[j]+1,r=R[j]-j+1,h=up[i][j];  
            ans+=h*(h+1)/2*(l+r)*l*r/2;
        }
    }
    printf("%lld\n",ans);
    return 0;
}