题目
分析
- 我们很容易就想到从头开始搜,如果向右扩展一个点可以的话,那么就用新点继续往后更新。
- 然后我们发现从两端开始,往中间更新也是可以的,感觉这俩是同理的。说不定还能双端搜索呢~
- 我不太清楚这个时间复杂度,反正觉得是正解了,然后就保龄了
- 按照这个思路,我们区间DP,用左右端点更新即可。就拿到了50pts的好成绩了。
- 我们可以想到这其实是一个前缀和的问题,那么我们把1-k这部分反过来当一个前缀和,把k+1 - n这部分当另一个前缀和。
- 我们把图形画出来会发现他像正弦曲线(山峰)一样。
- 那么对于一个可行点对(L,R)(L为上部分的位置,R为下部分的位置)只要
L处的前缀和+R与上一个波峰之间的最小值的前缀和 ≥ \geq ≥ 0 - 这样的话,我们可能会遇到降的幅度太大了,不合法了,那么我们就要用第二行的思想了,既然反着来是一样的,那么正难则反,考虑升的幅度太大了不是正和我意嘛。
- 只要反着做一遍,两端点都能到最大值,那么前后两端一连,这不就能到达了嘛。
代码
50分
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
long long pre[N];
bool dp[N][N];
int n,k;
inline long long read()
{
long long num=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1; ch=getchar();}
while(ch>='0'&&ch<='9') {num=(num<<1)+(num<<3)+ch-'0'; ch=getchar();}
return num*f;
}
int main()
{
freopen("eat.in","r",stdin);
freopen("eat.out","w",stdout);
int T=read();
while(T--)
{
n=read(),k=read(); pre[0]=0;
for(int i=1;i<=n;i++) pre[i]=pre[i-1]+read();
memset(dp,0,sizeof(dp));dp[k][k]=1;
for(int i=k;i>=1;i--)
for(int j=k;j<=n;j++) if(pre[j]-pre[i]>=0)
dp[i][j]|=dp[i+1][j]|dp[i][j-1];
dp[1][n]?puts("Yes"):puts("No");
}
return 0;
}
100分
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
long long pre[N],add[N],a[N],c[N],b[N];
int n,k,tot1,tot2;
long long num1[N],num2[N];
long long max1[N],max2[N];
long long min1[N],min2[N];
inline long long read()
{
long long num=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1; ch=getchar();}
while(ch>='0'&&ch<='9') {num=(num<<1)+(num<<3)+ch-'0'; ch=getchar();}
return num*f;
}
inline int check()
{
if(num1[tot1]+num2[tot2]<0) return 1;
int Bit1=1,Bit2=1;
min1[Bit1]=num1[1];min2[Bit2]=num2[1];
max2[Bit2]=max1[Bit1]=1;
for(int i=2;i<=tot1;i++)
if(num1[i]<num1[max1[Bit1]]) min1[Bit1]=min(min1[Bit1],num1[i]);
else max1[++Bit1]=i,min1[Bit1]=num1[i];
for(int i=2;i<=tot2;i++)
if(num2[i]<num2[max2[Bit2]]) min2[Bit2]=min(min2[Bit2],num2[i]);
else max2[++Bit2]=i,min2[Bit2]=num2[i];
int l=1,r=1;
while(l<Bit1||r<Bit2)
{
if(num1[max1[l]]+num2[max2[r]]<0) return 1;
if(l<Bit1&&min1[l]+num2[max2[r]]>=0) l++;
else if(r<Bit2&&min2[r]+num1[max1[l]]>=0) r++;
else return 1;
}
return 0;
}
int main()
{
freopen("eat.in","r",stdin);
freopen("eat.out","w",stdout);
int T=read();
while(T--)
{
n=read(),k=read();int cnt1=0,cnt2=0,ma1=0,ma2=0;tot1=tot2=0;
for(int i=1;i<=n;i++) c[i]=read();
for(int i=k;i>1;--i) a[++cnt1]=c[i];
for(int i=k+1;i<=n;i++) b[++cnt2]=c[i];
for(int i=1;i<=cnt1;i++) pre[i]=pre[i-1]+a[i];
for(int i=1;i<=cnt2;i++) add[i]=add[i-1]+b[i];
for(int i=1;i<=cnt1;i++) if(pre[i]>pre[ma1]) ma1=i;
for(int i=1;i<=cnt2;i++) if(add[i]>add[ma2]) ma2=i;//找最大值
for(int i=0;i<=ma1;i++) num1[++tot1]=pre[i];
for(int i=0;i<=ma2;i++) num2[++tot2]=add[i];
if(check()) {puts("No"); continue;}tot1=tot2=0;
for(int i=cnt1;i>=ma1;i--) num1[++tot1]=pre[i];
for(int i=cnt2;i>=ma2;i--) num2[++tot2]=add[i];
if(check()) {puts("No"); continue;}
puts("Yes");
}
return 0;
}