题目链接: codeforces-1202C.
题目描述
          
\;\;\;\;\;
在一个二维的格点图中,给出一个字符串
s
s
s 包含四种字符
‘
W
’
‘
S
’
‘
A
’
‘
D
’
‘W’‘S’‘A’‘D’
‘W’‘S’‘A’‘D’,一个字符为一个命令,分别表示向上、下、左、右四个方向走一格。这样,从一个格子出发,按照字符串顺序,走过一条轨迹,如题目中图片所示。可以用一个最小的矩形包含这条轨迹。
          
\;\;\;\;\;
问:在字符串中至多加入一个命令,使这个矩形的面积最小。输出面积的最小值。
           \;\;\;\;\; 1 ≤ ∣ s ∣ ≤ 2 ⋅ 1 0 5 1\leq |s| \leq 2 \cdot 10^{5} 1≤∣s∣≤2⋅105.
(题解)思路
      
\;\;\;
对于最初的轨迹而言,矩形的宽度取决于字符串中的
′
A
′
  
′
D
′
'A' \; 'D'
′A′′D′ 字符, 与其它字符无关。所以在只考虑宽度的情况下,可以转化为一维问题,这时只看字符串中的
′
A
′
  
′
D
′
'A' \; 'D'
′A′′D′ 两种字符。假设最初位于点 0 ,每遇到一个命令
‘
A
’
‘A’
‘A’ ,坐标
−
1
-1
−1,每遇到一个命令
‘
D
’
‘D’
‘D’ ,坐标
+
1
+1
+1.
      
\;\;\;
依次扫描字符串时,记录遇到命令
′
A
′
  
′
D
′
'A' \; 'D'
′A′′D′ 时的前缀和
s
u
m
sum
sum,矩形的左边界为
l
=
m
i
n
{
s
u
m
}
l=min\left \{ sum \right \}
l=min{sum},右边界
r
=
m
a
x
{
s
u
m
}
r = max \left \{ sum \right \}
r=max{sum},矩形的宽度
W
=
r
−
l
+
1
W = r - l + 1
W=r−l+1.
      
\;\;\;
现在考虑插入一个
′
D
′
'D'
′D′,即
+
1
+1
+1,要使矩形的宽度变小,就要在插入
+
1
+1
+1 后使最小值变大,即将左边界
l
l
l 右移,还要保证右边界不会右移。思考插入至何处可以满足这个条件。
s1 | A | A | A | A | D | D | D |
---|---|---|---|---|---|---|---|
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
sum = 0 | -1 | -2 | -3 | -4 | -3 | -2 | -1 |
s2 | D | D | D | A | A | D | A |
---|---|---|---|---|---|---|---|
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
sum = 0 | 1 | 2 | 3 | 2 | 1 | 2 | 1 |
      
\;\;\;
对于序列
s
1
s1
s1, 将
+
1
+1
+1 插入
′
A
′
'A'
′A′ 中间,最小值可变大,但最大值也会变大,插入
′
D
′
'D'
′D′ 中间,只会将最大值变大,均无用。
      
\;\;\;
对于序列
s
2
s2
s2, 将
+
1
+1
+1 插入下标
3
3
3 之前,会使最大值变大;其中有两个位置
4
,
6
4,6
4,6 均为最小值,若插入
4
−
6
4-6
4−6 之间,只能使位置
6
6
6 处的值变大,而序列的最小值不变。所以应将
+
1
+1
+1 插入位置
4
4
4 之前。
      
\;\;\;
综上所述,应将
+
1
+1
+1 插入最后一个最大值之后,第一个最小值之前。如果
M
a
x
′
s
  
l
a
s
t
p
l
a
c
e
<
M
i
n
′
s
  
f
i
r
s
t
p
l
a
c
e
Max's\;lastplace < Min's\;firstplace
Max′slastplace<Min′sfirstplace, 可插入
+
1
+1
+1 使最小值变大。矩形宽度
−
1
-1
−1.
      
\;\;\;
插入其他字符原理相同。
      
\;\;\;
注意点:
          
\;\;\;\;\;
当某宽度或长度方向的序列长度 < 2时,该方向无法再缩小。
          
\;\;\;\;\;
当宽度和长度均可缩小时,应判断缩小哪个使面积最小。
      
\;\;\;
时间复杂度:
O
(
∣
S
∣
)
O(|S|)
O(∣S∣)
代码
/*
nero
2019-8-22 00:52:50
long long 写的 %d WA1
*/
#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
#define lson(u) (u<<1)
#define rson(u) (u<<1|1)
#define Pi acos(-1)
#define iINF 0x3f3f3f3f
#define lINF 0x3f3f3f3f3f3f3f
#define EPS 0.000000001
#define pii pair<int,int>
typedef long long ll;
typedef unsigned long long ull;
const int MAXN = 200005;
int len, flag = 0;
char s[MAXN];
ll solve(char c1, char c2) {
int Min = 0, Max = 0, sum = 0;
int p_lastMax = -1, p_firstMax = -1, p_lastMin = -1, p_firstMin = -1;
int c = 0;
for(int i = 0; i < len; i++) {
bool ys = 0;
if(s[i] == c1) sum--, ys = 1;
if(s[i] == c2) sum++, ys = 1;
if(ys) {
c++;
if(sum == Max) {
p_lastMax = i;
}
if(sum > Max) {
p_firstMax = p_lastMax = i;
Max = sum;
}
if(sum == Min) {
p_lastMin = i;
}
if(sum < Min) {
p_firstMin = p_lastMin = i;
Min = sum;
}
}
}
ll tmp = Max - Min + 1;
if((c > 1) && (p_lastMax < p_firstMin || p_firstMax > p_lastMin)) {
tmp--;
flag++;
}
return tmp;
}
int main()
{
int T;
scanf("%d", &T);
while(T--) {
flag = 0;
scanf("%s", s);
len = strlen(s);
ll W = solve('W', 'S');
ll H = solve('A', 'D');
ll ans;
if(flag == 2) ans = min(W * (H+1), (W+1) * H);
else ans = W * H;
printf("%lld\n", ans);
}
return 0;
}