input:
6
7 4
-1 -2 -3 6 -2 -3 -1
3 1
232 -500 -700
7 4
-1 -2 -4 6 -2 -4 -1
8 4
-100 10 -7 6 -2 -3 6 -10
8 2
-999 0 -2 3 4 5 6 7
7 3
7 3 3 4 2 1 1
output:
YES
YES
NO
YES
NO
YES
题目大意:给我们一个长度为n的数组,并给我们一个数字k,表示我们起始位于a[k]位置,也就是我们初始的健康值为a[k],题目保证a[k]>=0,我们可以向左向右走,但是当走到一个位置的时候我们的健康值要加上当前位置x上的值a[x],注意每个位置上的值只有第一次经过的时候才会加入健康值,当第二次经过的时候就不用加了,问我们能否在健康值始终大于等于0的条件下走出这个数组,也就是说走到a[1]或者是a[n]位置。
解题思路:贪心。先选定一份方向,假设是先向左走,一直向左走直到不能继续走为止,走的过程中记录健康值取到最大的位置,将我们向左走的终点暂定为取到最大值的位置,然后再向右走,同样是走到不能走为止,记录在向左走取到的最大值的基础上,该过程中取到的最大值,然后以取到最大值的位置为基础再向左走,如此循环往复,如果最后能走到端点处就输出YES,否则如果左右两边都无法进行扩展了,级输出NO。
上代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=2e5+10;
long long t,n,k,a[N];
int main()
{
cin>>t;
while(t--)
{
cin>>n>>k;
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
if((k==1)||(k==n))
{
cout<<"YES"<<endl;
continue;
}
long long ans=a[k];
long long l=k,r=k;
bool flag=false;
while(l>=1&&r<=n)
{
long long ansl=ans;
long long posl=l,maxvl=ans;
for(int i=l-1;i>=1;i--)
{
if(ansl+a[i]>=maxvl)
{
maxvl=ansl+a[i];
posl=i;
}
ansl+=a[i];
if(ansl<0)
break;
if(i==1&&ansl>=0)
flag=true;
}
if(flag)
break;
long long posr=r,maxvr=maxvl;
long long ansr=maxvl;
for(int i=r+1;i<=n;i++)
{
if(ansr+a[i]>maxvr)
{
maxvr=ansr+a[i];
posr=i;
}
ansr+=a[i];
if(ansr<0)
break;
if(i==n&&ansr>=0)
flag=true;
}
if(flag)
break;
ans=maxvr;
if(l==posl&&r==posr)
break;
l=posl;
r=posr;
}
if(flag)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
return 0;
}