[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; } //数组越界 //完全背包更新的范围(假设有东西的区域可以更新) //