这题可以说是大开眼界了,模拟也是一个十分有思维量的题。
题的关键其实是如何统一这么多不同的情况。
题解:以左右最高板的高度进行讨论。
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
*/