P4147 玉蟾宫

题目背景

有一天,小猫 rainbow 和 freda 来到了湘西张家界的天门山玉蟾宫,玉蟾宫宫主蓝兔盛情地款待了它们,并赐予它们一片土地。

题目描述

这片土地被分成 N×M 个格子,每个格子里写着 R 或者 F,R 代表这块土地被赐予了 rainbow,F 代表这块土地被赐予了 freda。

现在 freda 要在这里卖萌。。。它要找一块矩形土地,要求这片土地都标着 F 并且面积最大。

但是 rainbow 和 freda 的 OI 水平都弱爆了,找不出这块土地,而蓝兔也想看 freda 卖萌(她显然是不会编程的……),所以它们决定,如果你找到的最大的土地面积为 S,它们每人给你 S 两银子。

输入格式

第一行两个整数 N,M,表示矩形土地有 N 行 M 列。

接下来 N 行,每行 M 个用空格隔开的字符 F 或 R,描述了矩形土地。

输出格式

输出一个整数,表示你能得到多少银子,即 3×S 的值。

输入输出样例

输入 #1复制

5 6 
R F F F F F 
F F F F F F 
R R R F F F 
F F F F F F 
F F F F F F

输出 #1复制

45

说明/提示

对于 50% 的数据,1≤N,M≤200。
对于 100% 的数据,1≤N,M≤1000。

实现代码:

#include<iostream>
#include<stack>
#include<cstring>

#define N 1010

using namespace std;

int n,m,f[N][N],maxx;
char c;
struct node
{
	int len,h;
}a[N];
stack<node> S;

void ask(int x)
{
	memset(a,0,sizeof(a));
	a[1].h=f[x][1],a[1].len=1;
	while(S.size())  S.pop();
	S.push(a[1]);
	for(int i=2;i<=m;i++)
	{
		int w=0;
		while(S.size()&&f[x][i]<=S.top().h)
		{
			w+=S.top().len;
			maxx=max(maxx,w*S.top().h);
			S.pop();
		}
		a[i].h=f[x][i],a[i].len=w+1;
		S.push(a[i]);
	}
	int w=0;
	while(S.size())
	{
		w+=S.top().len;
		maxx=max(maxx,S.top().h*w);
		S.pop();
	}
}

int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		{
			cin>>c;
			if(c=='F')  f[i][j]=f[i-1][j]+1;
		}
		
	for(int i=1;i<=n;i++)  ask(i);
	
	cout<<maxx*3<<endl;
	
	return 0;
}

P2866 [USACO06NOV] Bad Hair Day S

题目描述

农夫约翰有 N 头奶牛正在过乱头发节。

每一头牛都站在同一排面朝右,它们被从左到右依次编号为 1,2,⋯,N。编号为 i 的牛身高为 hi​。第 N 头牛在最前面,而第 1 头牛在最后面。

对于第 i 头牛前面的第 j 头牛,如果 hi​>hi+1​,hi​>hi+2​,⋯,hi​>hj​,那么认为第 i 头牛可以看到第 i+1 到第 j 头牛。

定义 Ci​ 为第 i 头牛所能看到的牛的数量。请帮助农夫约翰求出 C1​+C2​+⋯+CN​。

输入格式

输入共 N+1 行。

第一行为一个整数 N,代表牛的个数。
接下来 N 行,每行一个整数 ai​,分别代表第 1,2,⋯,N 头牛的身高。

输出格式

输出共一行一个整数,代表 C1​+C2​+⋯+CN​。

输入输出样例

输入 #1复制

6
10
3
7
4
12
2

输出 #1复制

5

说明/提示

数据规模与约定

对于 100% 的数据,保证 1≤N≤8×104,1≤hi​≤109。

 实现代码:

#include<bits/stdc++.h>
using namespace std;
int n,t;
long long ans;
stack <int> a;
int main() {
	cin>>n;
	for (int i=1; i<=n; i++) {
		cin>>t;
		while (!a.empty()&&a.top()<=t)  
			a.pop();
		ans+=a.size();
		a.push(t);
	}
	cout<<ans;
	return 0;
}

P1950 长方形

题目描述

小明今天突发奇想,想从一张用过的纸中剪出一个长方形。

为了简化问题,小明做出如下规定:

(1)这张纸的长宽分别为 n,m。小明将这张纸看成是由 n×m 个格子组成,在剪的时候,只能沿着格子的边缘剪。

(2)这张纸有些地方小明以前在上面画过,剪出来的长方形不能含有以前画过的地方。

(3)剪出来的长方形的大小没有限制。

小明看着这张纸,想了好多种剪的方法,可是到底有几种呢?小明数不过来,你能帮帮他吗?

输入格式

第一行两个正整数 n,m,表示这张纸的长度和宽度。

接下来有 n 行,每行 m 个字符,每个字符为 * 或者 .

字符 * 表示以前在这个格子上画过,字符 . 表示以前在这个格子上没画过。

输出格式

仅一个整数,表示方案数。

输入输出样例

输入 #1复制

6 4
....
.***
.*..
.***
...*
.***

输出 #1复制

38

说明/提示

【数据规模】

对 10% 的数据,满足 1≤n≤10,1≤m≤10

对 30% 的数据,满足 1≤n≤50,1≤m≤50

对 100% 的数据,满足 1≤n≤1000,1≤m≤1000

 实现代码:

#include<bits/stdc++.h>
using namespace std;
char ch;
long long l[1020],r[1020],h[1020],k[1020],n,m,top;
int d[1020][1020];
long long ans;
void ddzl(){
    top=0;
    for(int i=m;i>=1;i--){
        while(top!=0&&h[i]<=h[k[top]]) l[k[top]]=i,top--;
        top++;
        k[top]=i;
    }
    while(top) l[k[top]]=0,top--;
}
void ddzr(){
    top=0;
    for(int i=1;i<=m;i++){
        while(top!=0&&h[i]<h[k[top]]) r[k[top]]=i,top--;
        top++;
        k[top]=i;
    }
    while(top) r[k[top]]=m+1,top--;
}
void work(){
    ddzl();
    ddzr();
    for(int i=1;i<=m;i++){
        ans+=(i-l[i])*(r[i]-i)*h[i];
    } 
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>ch;
            if(ch=='*') d[i][j]=1;
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){h[j]++;if(d[i][j]) h[j]=0;}
        work();
    }
    cout<<ans;
}

P2032 扫描

题目描述

有一个 1×n 的矩阵,有 n 个整数。

现在给你一个可以盖住连续 k 个数的木板。

一开始木板盖住了矩阵的第 1∼k 个数,每次将木板向右移动一个单位,直到右端与第 n 个数重合。

每次移动前输出被覆盖住的数字中最大的数是多少。

输入格式

第一行两个整数 n,k,表示共有 n 个数,木板可以盖住 k 个数。

第二行 n 个整数,表示矩阵中的元素。

输出格式

共 n−k+1 行,每行一个整数。

第 i 行表示第 i∼i+k−1 个数中最大值是多少。

输入输出样例

输入 #1复制

5 3
1 5 3 4 2

输出 #1复制

5
5
4

说明/提示

对于 20% 的数据,1≤k≤n≤103。

对于 50% 的数据,1≤k≤n≤104。

对于 100% 的数据,1≤k≤n≤2×106,矩阵中的元素大小不超过 104 并且均为正整数。

 实现代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1000005;
int n,k;
struct node{int v,id;}a[N];
deque<node> qmin,qmax;
int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++)cin>>a[i].v,a[i].id=i;
    for(int i=1;i<=n;i++)
    {
        while(!qmax.empty()&&qmax.back().v<=a[i].v)qmax.pop_back();
        qmax.push_back(a[i]);
        if(qmax.front().id==i-k)qmax.pop_front();
        if(i>=k)cout<<qmax.front().v<<endl;
    }
    return 0;
}

P2216 [HAOI2007] 理想的正方形

提交答案加入题单复制题目

题目描述

有一个 a×b 的整数组成的矩阵,现请你从中找出一个 n×n 的正方形区域,使得该区域所有数中的最大值和最小值的差最小。

输入格式

第一行为 3 个整数,分别表示 a,b,n 的值。

第二行至第 a+1 行每行为 b 个非负整数,表示矩阵中相应位置上的数。每行相邻两数之间用一空格分隔。

输出格式

仅一个整数,为 a×b 矩阵中所有“ n×n 正方形区域中的最大整数和最小整数的差值”的最小值。

输入输出样例

输入 #1复制

5 4 2
1 2 5 6
0 17 16 0
16 17 2 1
2 10 2 1
1 2 2 2

输出 #1复制

1

说明/提示

矩阵中的所有数都不超过 1,000,000,000。

20% 的数据 2≤a,b≤100,n≤a,n≤b,n≤10。

100% 的数据 2≤a,b≤1000,n≤a,n≤b,n≤100。

 实现代码:

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 1e3 + 3;
int A[MAXN][MAXN];
int B[MAXN][MAXN];
int C[MAXN][MAXN];
int M[MAXN][MAXN], N[MAXN][MAXN];

int main(){
    int n, m, k;
    cin >> n >> m >> k;

    for(int i = 0;i < n;++ i){
        for(int j = 0;j < m;++ j){
            cin >> A[i][j];
            M[i][j] =  1e9;
            N[i][j] = -1e9;
        }
    }
    for(int i = 0;i <= (n - 1) / k;++ i){
        for(int j = 0;j <= (m - 1) / k;++ j){
            int u = i * k, v = min(n - 1, u + k - 1);
            int l = j * k, r = min(m - 1, l + k - 1);

            vector <tuple<int, int, int, int, int, int> > T = {
                { u, v, l, r, - k + 1, - k + 1 },
                { u, v, r, l, - k + 1, 0 },
                { v, u, l, r, 0, - k + 1 },
                { v, u, r, l, 0, 0 }
            };

            for(auto [l1, r1, l2, r2, d1, d2]: T){
                int t1 = 0, t2 = 0;

                t1 = r1 > l1 ? 1 : -1;
                t2 = r2 > l2 ? 1 : -1;
                for(int a = l1;a != r1 + t1;a += t1){
                    for(int b = l2;b != r2 + t2;b += t2){
                        B[a][b] = C[a][b] = A[a][b];
                        if(a != l1)
                            B[a][b] = min(B[a][b], B[a - t1][b]),
                            C[a][b] = max(C[a][b], C[a - t1][b]);
                        if(b != l2)
                            B[a][b] = min(B[a][b], B[a][b - t2]),
                            C[a][b] = max(C[a][b], C[a][b - t2]);
                        if(a + d1 >= 0 && b + d2 >= 0)
                            M[a + d1][b + d2] = min(M[a + d1][b + d2], B[a][b]),
                            N[a + d1][b + d2] = max(N[a + d1][b + d2], C[a][b]);
                    }
                }
            }
        }
    }

    int ans = 1e9;
    for(int i = 0;i < n - k + 1;++ i){
        for(int j = 0;j < m - k + 1;++ j){
            ans = min(ans, N[i][j] - M[i][j]);
        }
    }
    cout << ans << endl;
    return 0;
}
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐