1. 程式人生 > >[NOIP2014][題解]飛揚的小鳥

[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; } //陣列越界 //完全揹包更新的範圍(假設有東西的區域可以更新) //