B. Most socially-distanced subsequence
题意:
给出一个数组
a
a
a,找到数组中的一个子序列
s
s
s(长为
x
x
x),满足“
∑
i
=
1
x
∣
s
[
i
]
−
s
[
i
−
1
]
∣
\sum_{i=1}^x|s[i]-s[i-1]|
∑i=1x∣s[i]−s[i−1]∣最大”。如果有多个答案就出
x
x
x较小的子序列
思路:
我们观察一个递增的序列
s
=
{
1
,
2
,
3
,
4
,
6
}
s = \{1,2,3,4,6\}
s={1,2,3,4,6},则:
∑
i
=
1
x
∣
s
[
i
]
−
s
[
i
−
1
]
∣
=
5
\sum_{i=1}^x|s[i]-s[i-1]| = 5
∑i=1x∣s[i]−s[i−1]∣=5,因为
s
[
i
]
>
s
[
i
−
1
]
s[i] > s[i-1]
s[i]>s[i−1],所以当我们拆开公式,发现只剩下
s
[
5
]
−
s
[
1
]
=
6
−
1
=
5
s[5] - s[1] = 6-1 = 5
s[5]−s[1]=6−1=5,同理当序列递减也有同样的结论。(解决了最短的问题)。
序列
{
x
,
z
,
y
}
\{x,z,y\}
{x,z,y},如果在数轴上
z
z
z在
x
,
y
x,y
x,y中间(如
z
1
z_1
z1),
∣
y
−
z
∣
+
∣
z
−
x
∣
=
y
−
x
|y-z|+|z-x| = y-x
∣y−z∣+∣z−x∣=y−x,如果像
z
2
z_2
z2一样,我们可以发现
∣
y
−
z
∣
+
∣
z
−
x
∣
=
z
−
y
+
z
−
x
|y-z|+|z-x| = z-y+z-x
∣y−z∣+∣z−x∣=z−y+z−x,这个找到
∑
i
=
1
x
∣
s
[
i
]
−
s
[
i
−
1
]
∣
\sum_{i=1}^x|s[i]-s[i-1]|
∑i=1x∣s[i]−s[i−1]∣最大和
x
x
x最小用到的方法都是一样的。
剩下的就是我们的模拟了,找出数组a中连续的递增或递减的序列,除去中间的元素,不影响结果。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+10;
const int inf = 0x7ffffff;
const ll INF = 0x7fffffffffff;
ll f[][2] = {1, 0, 0, 1, -1, 0, 0, -1}, n, m;
ll s[N];
int read() {
int x = 0; int f = 1; char s = getchar();
while(s < '0' || s > '9') {if(s == '-') f = -1; s = getchar();}
while(s >= '0' && s <= '9') {x = (x << 3) + (x << 1) + s - 48; s = getchar();}
return x * f;
}
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
int t;
cin >> t;
while(t--) {
n = read();
m = n;
for(int i=1; i<=n; i++) s[i] = read();
if(n == 2) {
cout << 2 << endl;
for(int i=1; i<=n; i++) cout << s[i] << ' ';
cout << endl;
continue;
}
int i = 1, j = 2, k = 3;//从数组下标1,2,3开始扫描,每三个三个比较。
while(k <= n) {
//判断是否连续递增或
if(s[j]>s[i] && s[k]>s[j] || s[j]<s[i] && s[j]>s[k]) {
m--;
s[j] = -1;/做标记。
j++, k++;
}
else i = j, j++, k++;
}
cout << m << endl;
for(int i=1; i<=n; i++) {
if(s[i] != -1) cout << s[i] << ' ';
}
cout << endl;
}
return 0;
}