zoukankan      html  css  js  c++  java
  • P4147 玉蟾宫

    题目背景

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

    并赐予它们一片土地。
    题目描述

    这片土地被分成 \(N\times M\) 个格子,每个格子里写着 'R' 或者 'F',R 代表这块土地被赐予了 rainbow,

    F 代表这块土地被赐予了 freda。现在 freda 要在这里卖萌。。。它要找一块矩形土地,

    要求这片土地都标着 'F' 并且面积最大。但是 rainbow 和 freda 的 OI 水平都弱爆了,找不出这块土地,

    而蓝兔也想看 freda 卖萌(她显然是不会编程的……),所以它们决定,如果你找到的土地面积为 S,它们每人给你 S 两银子。

    输入格式

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

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

    输出格式

    输出一个整数,表示你能得到多少银子,即 (3\times \text{最大 'F' 矩形土地面积}) 的值。

    输入输出样例

    输入 #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%100%100% 的数据,1≤N,M≤1000

    我们可以想到O(n^4)的暴力。

    枚举每个矩形的左上角和右下角,然后算出每个矩形的贡献,

    最后在对每个矩形的贡献取个max便是最后的答案

    但这样只能过一半的数据,然后我们就要考虑优化。

    我们可以对每个点求出他向下所能延伸的高度,也就是矩形的高。

    那么怎么确定矩形的宽呢?

    如果,我们能求出他所能向左和向右能延伸的长度,那么这个矩形的贡献不就很好的求出来了吗?

    一个点能向左右两边延伸,当且仅当左右两边能向下延伸的高度比他大的时候。

    我甩给你一张图:

    颜色表示每个点能向下延伸的最大长度,看看这张图应该能明白吧(

    自己可以手动模拟一下。

    求序列中第一个比他小的数,那这不是单调栈吗?

    所以,我们对每一行从左往右跑一边单调栈,在反过来跑一边就可以求出每个点的贡献

    最后答案一定不要忘记乘三(当初我傻乎乎的调了半天才发现没乘三)

    代码

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    char ch; 
    int n,m,top,ans;
    int sta[1010],ls[1010],rs[1010],h[1010][1010];
    inline int read()
    {
    	int s = 0, w = 1; char ch = getchar();
    	while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9'){s = s * 10+ch -'0'; ch = getchar();}
    	return s * w;
    }
    int main()
    {
        n = read(); m = read();
        for(int i = 1; i <= n; i++)
        {
        	for(int j = 1; j <= m; j++)
        	{
        		cin>>ch;
        		if(ch == 'F') h[i][j] = h[i-1][j] + 1;//求出每个点能向下延伸的高度也就是矩形的高
        	}
        	top = 0; sta[++top] = 0;
        	for(int j = 1; j <= m; j++)//正着跑一遍单调栈求出每个点能向左延伸的长度
        	{
        		while(top && h[i][sta[top]] >= h[i][j]) top--;
        		ls[j] = sta[top]; sta[++top] = j; 
        	}
        	top = 0; sta[++top] = m+1;
        	for(int j = m; j >= 1; j--)//反着跑一遍单调栈求出每个点向右能延伸的长度
        	{
        		while(top && h[i][sta[top]] >= h[i][j]) top--;
        		rs[j] = sta[top]; sta[++top] = j;
        	}
        	for(int j = 1; j <= m; j++)
        	{
        		ans = max(ans,3 * h[i][j] * (rs[j]-ls[j]-1));//统计答案
        	}
        }
    	printf("%d\n",ans);
    	return 0;
    }
    

    听别的大佬用悬线法切了这道题。

    但蒟蒻我太菜了,没学会。

    先占上坑吧,后期再补。

    ENDING

  • 相关阅读:
    多条件搜索问题 -sql拼接与参数化查询
    MVC View中获取action、controller、area名称、参数
    Hadoop权限认证的执行流程
    Java API操作HA方式下的Hadoop
    利用HBase的快照功能来修改表名
    hive两大表关联优化试验
    Spark SQL与Hive on Spark的比较
    Spark的RDD原理以及2.0特性的介绍
    hbase Java API 介绍及使用示例
    初识Spark2.0之Spark SQL
  • 原文地址:https://www.cnblogs.com/genshy/p/13509938.html
Copyright © 2011-2022 走看看