luogu_ P1941 飞扬的小鸟

传送门:https://www.luogu.org/problem/P1941

关于此题,只能说细节吧。

  1. 一次可以按很多次。随意转移时可以运用完全背包的思想,在这里你不能因为某个状态不合法就直接否了,因为他只是不能像下一列转移,我们需要用它对同一列转移
  2. 对于超过m的高度要格外注意,不要漏掉情况。
  3. n和m不能搞反啊......
  4. 对于第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;
}
View Code
原文地址:https://www.cnblogs.com/coclhy/p/11731336.html