传送门:https://www.luogu.org/problem/P1941
关于此题,只能说细节吧。
- 一次可以按很多次。随意转移时可以运用完全背包的思想,在这里你不能因为某个状态不合法就直接否了,因为他只是不能像下一列转移,我们需要用它对同一列转移
- 对于超过m的高度要格外注意,不要漏掉情况。
- n和m不能搞反啊......
- 对于第1点,你要确认你所用的转移点不是经过下降得来的。关于这一点你可以在更新下一列状态的同时做完全背包,因为完全可以保证下一列的同一高度绝对不会是下降得来(至今没有比它高的呢。
然后转移方程什么的,就很显然了。初始状态f[0][0]记得赋值为极大值,那个状态是不合法滴!
//代码真心丑,费时有点长。。。。。 #include<cstdio> #include<algorithm> #include<cstring> #define R register using namespace std; int n,m,k,ans=1e9,du[11000],dd[11000],s[11000],up[11000],down[11000],f[11000][1100]; int main (){ scanf("%d%d%d",&n,&m,&k); for(R int i=0;i<n;i++){ scanf("%d%d",&du[i],&dd[i]); up[i]=m;down[i]=1; } up[n]=m;down[n]=1; for(R int x,i=1;i<=k;i++){ scanf("%d",&x); s[x]++; scanf("%d%d",&down[x],&up[x]); down[x]++; up[x]--; } for(R int i=1;i<=n;i++) s[i]+=s[i-1]; memset(f,0x3f,sizeof(f)); for(R int i=1;i<=m;i++) f[0][i]=0; for(R int i=0;i<n;i++){ for(R int j=1;j<=m;j++){ f[i+1][(j+du[i]>m?m:j+du[i])]=min(f[i+1][(j+du[i]>m?m:j+du[i])],f[i+1][j]+1); if(j>=down[i]&&j<=up[i]){ if(f[i][j]<1e9) f[i+1][j+du[i]>m?m:j+du[i]]=min(f[i+1][j+du[i]>m?m:j+du[i]],f[i][j]+1); if(f[i][j]<1e9&&j-dd[i]>=down[i+1]&&j-dd[i]<=up[i+1]) f[i+1][j-dd[i]]=min(f[i+1][j-dd[i]],f[i][j]); } else{ f[i][j]=f[10100][1010]; } } } for(R int i=1;i<=m;i++){ if(i>=down[n]&&i<=up[i]) ans=min(ans,f[n][i]); else f[n][i]=f[10100][1010]; } if(ans<1e9){ printf("1 %d ",ans); } else{ printf("0 "); for(R int i=n-1;i>=1;i--){ for(R int j=1;j<=m;j++){ if(f[i][j]<1e9){ printf("%d ",s[i]); exit(0); } } } } return 0; }