非常典型的CF题,代码量不大,但细节扣得很死,题也容易读错
思路(分类讨论):
看到一个往低处走,一个往高处走,尽可能走的最远——>想到最长单调子列
以单调子列长度为依据讨论:
1、A选非最长列上一点,则B可选最长列上最低点,A必败
2、A选最长列上一点,
{1} A选最长列中间的点,B直接选在下方,A必败
{2}A选最长列最高点
(1)B选另一条最长列,A必败
(2)最长列数量唯一,B和A选中同一条最长列。
[1]A和B对着走,取决于路径奇偶
[2]A和B同向走,条件是B知道和A对着走必败。则取决于和最长列最高点相连的另一列的长度。
由于边界不是循环的(1不能走到n),所以需要特判边界
1、A如果要选边界所在数列,B可直接选在下方堵死,A必败——>A不可能选边界所在列(抛去 除边界点外的另一个端点)
{1}如果边界列为最长列,B可选在最低点,A必败
{2}如果边界列为非最长列,B也不会选。
下面需要根据条件进行合并,方便写代码
综上,
1、若边界是最长列,A必败。
2、A只可能选最长列的最高点。
{1}找到最高点数量,若数量不唯一,A必败
{2}若唯一,判断奇偶、另一列的长度,讨论A败的情况。
注意:最长列数量不对应最高点数量。如 /\ 形,两条最长列,但最高点只有一个,
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll k,n,m,x,y,ans,ans2,lin,a[100005];
double ansf,b[100005];
bool up;
int i,j,l,r,T,mk;
char ch[150];
void cmpupdate(int sx)
{
if(a[i]>a[i-1])
{
if(up)lin++;
else lin=1;
up=1;
}else
{
if(!up)lin++;
else lin=1;
up=0;
}
if(sx==1){if(lin>ans){ans=lin;}}
if(sx==2)
{
if(lin==ans)
{
ans2++;
if(up){while(i<n&&a[i+1]<a[i])i++;up=0; }
}
}
if(sx==3)
{
if(lin==ans)
{mk=i;
if(up){
while(i<n&&a[i+1]<a[i])i++;
mk=i-mk;
} else
{
while(i>1&&a[i-1]<a[i])i--;
mk=mk-i;
}
i=n;
}
}
}
int main()
{
scanf("%lld",&n);
scanf("%lld",&a[1]);
scanf("%lld",&a[2]);
i=2;
lin=up=0;
cmpupdate(1);
ans=1;
for(i=3;i<=n;i++)
{
scanf("%lld",&a[i]);
cmpupdate(1);
}
lin=up=0;
for(i=2;i<=n;i++)
{
cmpupdate(2);
}
i=2;
while(a[i]<a[i-1]&&i<=n)i++;
if(i-2==ans)ans2=0;
i=n;
while(a[i]>a[i-1]&&i>=1)i--;
if(n-i-1==ans)ans2=0;
if(ans2==0||ans2>1){
printf("0");
return 0;
}
if(ans%2==1)printf("0");
else {
for(i=2;i<=n;i++)
{
cmpupdate(3);
}
ans--;
if(ans>=mk)printf("0");else
printf("1");
}
}