[NOIP2014][题解]飞扬的小鸟

题目链接:https://www.luogu.org/problemnew/show/P1941

思路:

预处理x=1的情况。

先做完全背包再做0/1背包。

时间复杂度O(n*m),空间复杂度O(n*m).

其实空间复杂度可以用滚动数组优化成O(m)

原理同0/1背包和完全背包的优化。

具体可以看背包9讲。

代码:

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<cmath>
#include<algorithm>
#define R register
#define ll long long int
using namespace std;
const int N=10005,M=1005;
const int INF=0x3f3f3f3f;
int n,m,k,up[N],dn[N],l[N],r[N],f[N][M],ans1=INF,ans2,sum[N];//l下  r上
int main(){
    scanf("%d%d%d",&n,&m,&k);
    for(R int i=0;i<=n-1;i++)
    scanf("%d%d",&up[i],&dn[i]);
    for(R int i=0;i<=n;i++)
    l[i]=1,r[i]=m;
    for(R int i=1;i<=k;i++)
    {
        R int x;
        scanf("%d",&x);
        scanf("%d%d",&l[x],&r[x]);
        l[x]++;r[x]--;
        sum[x]++;
    }
    for(R int i=1;i<=n;i++)
    sum[i]+=sum[i-1];
    memset(f,0x3f,sizeof(f));
    for(R int i=1;i<=m-dn[0];i++)
    if(i<=r[1]&&i>=l[1])f[1][i]=0;
    
    for(R int i=m-dn[0]+1;i<=m;i++)
    if(i>=1+up[0]&&i<=r[1]&&i>=l[1])
    f[1][i]=1;
    
    for(R int i=2;i<=n;i++){
        for(R int j=l[i-1];j<=r[i];j++)
        {    
            if(j==m)
            for(R int k=m-up[i-1];k<=m;k++)
            {    
                f[i][j]=min(f[i][j],min(f[i-1][k]+1,f[i][k]+1));
                if(f[i][j]+5000<INF)ans2=sum[i];
            }
            if(j-up[i-1]>0)
            f[i][j]=min(f[i][j],min(f[i-1][j-up[i-1]]+1,f[i][j-up[i-1]]+1));
            if(f[i][j]+5000<INF)  ans2=sum[i];
        }    
        for(R int j=l[i];j<=r[i];j++)
        {
            if(j+dn[i-1]>=l[i-1]&&j+dn[i-1]<=r[i-1])
            f[i][j]=min(f[i][j],f[i-1][j+dn[i-1]]);
            if(f[i][j]+5000<INF)  ans2=sum[i];
        }
        for(R int j=l[i-1];j<l[i];j++)
        f[i][j]=INF;
    }
    for(R int i=1;i<=m;i++)
    ans1=min(ans1,f[n][i]);
    if(ans1<0x3f3f3f3f)
    printf("1\n%d",ans1);
    else printf("0\n%d",ans2);
    return 0;
}
//数组越界
//完全背包更新的范围(假设有东西的区域可以更新)
//

猜你喜欢

转载自www.cnblogs.com/sky-zxz/p/9905173.html