UVA10366(细节模拟)

本文介绍了一种处理复杂地形积水问题的模拟算法。通过对比左右两侧最高障碍物的高度,采用逆序计算的方法来解决不同场景下的积水计算难题,并提供了一个具体的实现方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这题可以说是大开眼界了,模拟也是一个十分有思维量的题。

题的关键其实是如何统一这么多不同的情况。

题解:以左右最高板的高度进行讨论。

1、最高板高度相同,那么只需讨论2个最高板到边界的区域谁大,ans中再加上中间那一块。计算两边区域谁大时用逆序计算,这样可以直接算出1 3 2这种复杂情况。

2、最高板高度不相同,那肯定是流向低处,流向低处的同时需要判断是否会溢向另一边,假设A、B两块最高板,A>B,找到A这一边第一块不小于B的板C,如果C大于B就不会溢过去,C=B就会溢过去,至于溢过去多少,以一个十分巧妙的循环来判断,只要C之后的板<=B,都会溢过去,大于B就立刻终止,所以就不需要单独套路C与B的大小,只要从第一块不小于B的板开始,判断是否<=B,满足这个就表示可以溢过去,也就包含了之后的板与B相等的情况。溢过去之后判断溢过去的量与另一边量的大小,假设分别记为P、Q。 如果P > Q 说明Q满了P也不会满,所以Q的速度要减半,反之,最后的结果就是P+Q(好好想想都能想明白)。



#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <map>
#include <set>
#include <queue>
#include <vector>
#define mod  1000000007
#define INF  0x3f3f3f3f
#define fuck() (cout << "----------------------------------------" << endl)
using namespace std;
const int maxn = 3000 + 5;
int l,r,n,ln,rn;
int maxr,maxl;//左右最大板的长度
int maxindexr,maxindexl;//左右最大板的下标(第几块板)
int lb[maxn];
int rb[maxn];
int solve()//一共两种情况:1、左右两块最高板一样高,2、不一样高
{
    int ans = 0;
    if(maxr == maxl) //情况1
    {
        ans += (maxindexr + maxindexl - 1) * 2 * maxr;
        int ans1 = 0, ans2 = 0;
        int k = rb[rn], t = lb[ln];
        for(int i=rn; i>maxindexr; i--)//倒着来就可以解决之后的板比前面的高问题
        {
            ans1 += k;
            k = max(k,rb[i-1]);
        }
        for(int i=ln; i>maxindexl; i--)
        {
            ans2 += t;
            t = max(t,lb[i-1]);
        }
        return ans + min(ans1,ans2) * 2 * 2;
    }
    else // 情况2
    {
        int ans1 = 0, ans2 = 0;
        int q = 1, p = 1;
        int T = min(maxr, maxl);
        while(q < rn && rb[q] < T)//右边最高的边之前的比左边最高的边高的那条
            q++;
        while(p < ln && lb[p] < T)//同理左边
            p++;
        //上面两个while算出来其实是便于统一,我觉得这个思想非常重要,其实特殊情况都可以归结为一般情况
        if(maxr > maxl) //右边的比左边的高
        {
            int k = rb[q], t = lb[ln];
            for(int i=q; rb[i]<=maxl; i++)//倒着来就可以解决之后的板比前面的高问题
            {
                ans1 += k;
                k = max(k,rb[i+1]);
            }
            for(int i=ln; i>maxindexl; i--)
            {
                ans2 += t;
                t = max(t,lb[i-1]);
            }
        }
        else
        {
            int k = lb[p], t = rb[rn];
            for(int i=p; lb[i]<=maxr; i++)//算出溢过去的量,等于号的情况才有可能溢过去,觉得这个非常巧妙
            {
                ans1 += k;
                k = max(k,lb[i+1]);
            }
            for(int i=rn; i>maxindexr; i--)
            {
                ans2 += t;
                t = max(t,rb[i-1]);
            }
        }
        //ans1 大于 ans2代表会溢到另一边,但是另一边需要填充的更多,所以低的那边先结束,速度也就慢了一倍
        //小于可以理解为左右都要填
        ans = ans1 > ans2 ? ans2*2 : ans1 + ans2;
        return ans * 2 + (p + q - 1) * 2 * T;
    }
}
int main()
{

    while(scanf("%d%d",&l,&r) == 2 && l)
    {
        maxr = maxl = 0;
        n = (r - l) / 2 + 1;
        ln = (1 - l) / 2;
        rn = (r + 1) / 2;
        for(int i=l; i<=r; i+=2)//存板并且找出左右两边的最大板
        {
            if(i < 0)
            {
                scanf("%d",&lb[(1 - i) / 2]);
                if(lb[(1 - i) / 2] >= maxl)//等于号的意思是找到离0最近的板,没有就WA
                {
                    maxl = lb[(1 - i) / 2];
                    maxindexl = (1 - i) / 2;
                }
            }
            else
            {
                scanf("%d",&rb[(i + 1) / 2]);
                if(rb[(i + 1) / 2] > maxr)
                {
                    maxr = rb[(1 + i) / 2];
                    maxindexr = (1 + i) / 2;
                }
            }
        }
        //cout << maxl << "  " << maxindexl << "  " << maxr << "  " << maxindexr << endl;
        printf("%d\n",solve());
    }
}
/*
-1 1
3 5
-3 3
4 3 2 1
-3 5
1 2 2 1 1
0 0
 */







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值