用f[i][j]表示小鸟从开始到(i,j)的位置最小点击次数,具体转移方程见代码
注意:要判断是否超过上边界
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+5;
const int maxm=2005;
int n,m,p;
int up[maxn],down[maxn],low[maxn],high[maxn];
int f[maxn][maxm];
int pipe[maxn];
int main()
{
freopen("a.in","r",stdin);
scanf("%d%d%d",&n,&m,&p);
for(int i=1;i<=n;i++) scanf("%d%d",&up[i],&down[i]);
for(int i=1;i<=n;i++) low[i]=1,high[i]=m;
int x,y,z;
for(int i=1;i<=p;i++)
{
scanf("%d%d%d",&x,&y,&z);
pipe[x]=1;
low[x]=y+1;
high[x]=z-1;
}
memset(f,0x3f,sizeof(f));
for(int i=1;i<=m;i++) f[0][i]=0;
for(int i=1;i<=n;i++)
{
for(int j=up[i]+1;j<=m+up[i];j++)
f[i][j]=min(f[i][j],min(f[i-1][j-up[i]]+1,f[i][j-up[i]]+1));//当前位置是上一次上升或者这次上升得来的
for(int j=m+1;j<=m+up[i];j++)
f[i][m]=min(f[i][m],f[i][j]); //处理超过上边界的部分
for(int j=1;j<=m-down[i];j++)
f[i][j]=min(f[i][j],f[i-1][j+down[i]]); //当前状态可能是上一次下降得到的
for(int j=1;j<low[i];j++) f[i][j]=f[0][0];
for(int j=high[i]+1;j<=m;j++) f[i][j]=f[0][0];
}
int ans=f[0][0];
for(int i=1;i<=m;i++) ans=min(ans,f[n][i]);
if(ans!=f[0][0]) printf("1\n%d\n",ans);
else
{
int pos=0; ans=0;
for(int i=n;i>=1,!pos;i--)
for(int j=1;j<=m;j++)
if(f[i][j]<f[0][0]) {pos=i; break;}
for(int j=1;j<=pos;j++)
if(pipe[j]) ans++;
printf("0\n%d\n",ans);
}
return 0;
}