问题描述
序列 X X X,划分成两个字序列 A , B A,B A,B,其中惩罚是 A , B A,B A,B之中, A [ i ] < A [ i + 1 ] , B [ i ] < B [ i + 1 ] A[i] < A[i+1], B[i] < B[i+1] A[i]<A[i+1],B[i]<B[i+1]的个数
思路
-
拆分 X X X,实际上是个在线的过程,不断的从 X X X中拿数字往 A , B A,B A,B之中填。
-
我们假设 A , B A,B A,B的最后一个数字为 A l , B l A_l,B_l Al,Bl, 针对元素 X [ i ] X[i] X[i]的插入,下列三种情况进行不同的讨论,不失一般性,我们假设 A l < = B l A_l <= B_l Al<=Bl。
情况1: X [ i ] < = A l X[i] <= A_l X[i]<=Al
添 X [ i ] X[i] X[i]到 A A A里,因为 B l B_l Bl可接受的范围一定更广泛情况2: X [ i ] > B l X[i] > B_l X[i]>Bl
添 X [ i ] X[i] X[i]到 A A A里,因为添加到 B B B的末尾,会损失一个大一点的数字情况3: A l < X [ i ] < = B l A_l < X[i] <= B_l Al<X[i]<=Bl
添 X [ i ] X[i] X[i]到 B B B里,不论到A和B得会到一个负分,该决策优于添加到A,这个在文末证明
代码
void solve()
{
int n;
cin >> n;
vector<int> v(n + 1);
for (int i = 1; i <= n; i++)
{
cin >> v[i];
}
int a, b;
a = b = INT_MAX;
int penalty = 0;
for (int i = 1; i <= n; i++)
{
if (a > b) // a <= b
{
swap(a, b);
}
if (v[i] <= a)
{
a = v[i];
}
else if (v[i] <= b)
{
b = v[i];
}
else
{
penalty++;
a = v[i];
}
}
cout << penalty << "\n";
}
证明
情况3我们可以比较两种决策,
决策1:插入A
决策2:插入B
决策2的收益来的比较短,比如下面这种场景
A
:
[
3
]
A:[3]
A:[3]
B
:
[
8
]
B:[8]
B:[8]
X
[
i
]
=
5
X[i] = 5
X[i]=5
A
:
[
3
]
A:[3]
A:[3]
B
:
[
8
,
5
]
B:[8, 5]
B:[8,5]
如果我们下一个数字
X
[
i
+
1
]
X[i+1]
X[i+1]为7,就得到1点负面收益
A
:
[
3
,
7
]
A:[3, 7]
A:[3,7]
B
:
[
8
,
5
]
B:[8, 5]
B:[8,5]
决策1的收益在与后期,比如:
A
:
[
3
]
A:[3]
A:[3]
B
:
[
8
]
B:[8]
B:[8]
X
[
i
]
=
5
X[i] = 5
X[i]=5
A
:
[
3
,
5
]
A:[3, 5]
A:[3,5]
B
:
[
8
]
B:[8]
B:[8]
如果我们下一个数字
X
[
i
+
1
]
X[i+1]
X[i+1]为7,那么我们决策1就会得到收益
A
:
[
3
,
5
]
A:[3,5]
A:[3,5]
B
:
[
8
,
7
]
B:[8, 7]
B:[8,7]
但是如果我们下个数字大于8, 或者小于等于5,我们决策2和决策1会等价,并且决策2会少一点penalty。
比较上面情况, 决策2全方面的大于决策1
证毕