题目链接
题意:一个大小为
n
n
n的数组
p
p
p (
p
p
p是
1
,
2
,
3
,
.
.
.
,
n
{1,2,3,...,n}
1,2,3,...,n的一个排列),现在
A
,
B
A,B
A,B进行这样一个游戏,
A
A
A先选定一个初始位置
x
x
x,
B
B
B再选定一个初始位置
y
y
y(选定的位置是公开的),然后开始移动,移动规则如下:
A
A
A: 选定
x
x
x为
A
A
A移动到的位置,且需满足
x
≠
y
,
1
≤
x
′
≤
n
,
∣
x
−
x
′
∣
=
1
,
p
[
x
′
]
<
p
[
x
]
x≠y,1 \le x'\le n,|x-x'|=1,p[x']<p[x]
x=y,1≤x′≤n,∣x−x′∣=1,p[x′]<p[x]
B
B
B: 选定
y
y
y为
B
B
B移动到的位置,且需满足
y
≠
x
,
1
≤
y
′
≤
n
,
∣
y
−
y
′
∣
=
1
,
p
[
y
′
]
>
p
[
y
]
y≠x,1\le y'\le n,|y-y'|=1,p[y']>p[y]
y=x,1≤y′≤n,∣y−y′∣=1,p[y′]>p[y]
当一方不能移动时,输掉游戏。问先手的胜负。
思路:为了方便叙述,我把这个问题看作一个在山峰上移动的过程,A只能下坡,B只能上坡,记
l
l
l为最长单调序列的长度(最长坡的长度),
c
c
c为最长单调序列的数量。并且约定奇数轮A移动,偶数轮B移动。
显然A的最优选择是从山峰开始,B的最优选择是从最底下开始,我们不难发现:
- 当最长单调序列数量大于2时,即 c > 2 c>2 c>2时,A选择某一个最高山峰(某最长单调序列的最大值)后,B可以选另一个最高山峰对应的谷底(另一最长单调序列的最小值),这样经过 c c c回合后,A就无法继续移动了,即先手负。
- 当最长单调序列数量等于1时,即 c = 1 c=1 c=1时,A选择一个最高山峰,B都可以控制AB间距离为偶数,这样就使得 ∣ A B ∣ / 2 |AB|/2 ∣AB∣/2轮后,A无法选择。 例如序列 1 , 2 , 6 , 5 , 4 , 3 {1,2,6,5,4,3} 1,2,6,5,4,3,A选择7,那么B直接选择4,这样如果A选择向左侧移动,那显然3回合后就无法移动;如果A选择向右侧移动,那四轮以后A站在6的位置上,B站在5的位置上,第五轮到A时,A无法移动,先手负
- 当最长单调序列数量等于2时,即 c = 2 c=2 c=2时,只有两个单调序列类似于 p m − l + 1 < p m − l + 2 < ⋯ < p m > p m + 1 > ⋯ > p m + l − 1 p_{m-l+1}<p_{m-l+2}<\cdots<p_m>p_{m+1}>\cdots>p_{m+l-1} pm−l+1<pm−l+2<⋯<pm>pm+1>⋯>pm+l−1,A才有可能赢(否则可以参考 c > 2 c>2 c>2的情况让先手负),那么需要考虑最长单调序列长度的奇偶性,如果 c % 2 = 0 c\%2=0 c%2=0,那么无论是A与B同向而行还是相向而行都会在偶数轮让A无路可走,即 先手负;如果 c % 2 = 1 c\%2=1 c%2=1,那么A显然第一轮选择山峰,如果随后B选择了最低点,那A就控制自己与B相向而行,由于长度是奇数,最后B会无法选择,如果B不选择最低点而是控制AB距离为偶数,那A随后就可以选择和B同向移动,这样A能移动的长度会比B长,所以这种情况下先手胜。
总结以上情况,认真分类讨论,不难得出结论。
AC代码:
#include <bits/stdc++.h>
#define pcc pair<char, char>
#define pii pair<int, int>
#define vi vector<int>
#define vl vector<ll>
#define rep(i, x, y) for (int i = x; i < y; i++)
#define per(i, x, y) for (int i = x; i >= y; i--)
#define rep0(i, n) for (int i = 0; i < (n); i++)
#define per0(i, n) for (int i = (n)-1; i >= 0; i--)
#define mp make_pair
#define pb push_back
#define F first
#define S second
#define sz(x) (x).size()
#define all(x) (x).begin(), (x).end()
#define ll long long
#define ull unsigned long long
#define db double
#define ld long double
using namespace std;
inline int read() {
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
const double eps = 1e-9;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 10;
const int MAX = 1e5;
const ll INF = 0x3f3f3f3f3f3f3f;
/***************main****************/
ll T = 1;
ll m, n;
ll a[maxn], l[maxn], r[maxn], mi[maxn];
int main() {
n = read();
ll cnt1 = 0, cnt2 = 0;
rep(i, 0, n) {
a[i] = read();
l[i] = r[i] = 1;
}
ll ma = 0;
rep(i, 1, n) if (a[i] > a[i - 1]) l[i] = l[i - 1] + 1;
per(i, n - 2, 0) if (a[i] > a[i + 1]) r[i] = r[i + 1] + 1;
rep(i, 0, n) ma = max(max(l[i], r[i]), ma);
rep(i, 0, n) if (l[i] == ma || r[i] == ma) {
if (l[i] == r[i]) cnt1++;
cnt2++;
}
if (cnt1 + cnt2 != 2)
cout << 0 << endl;
else if (cnt1 != 1)
cout << 0 << endl;
else if (ma & 1)
cout << 1 << endl;
else
cout << 0 << endl;
return 0;
}