【[NOIP2014 Day1 T3]飞扬的小鸟】背包啦啦啦
第一次看还是感觉很难的。。。仔细分析起来,发现自己还是太弱了。。。
传送门:https://www.luogu.org/problemnew/show/P1941
状态;f[i][j]第i格,达到高度j所需最小的点击次数
70%分 : f[i][j] = min: f[i-1][j+y[i]] , f[i-1][j-k*x[i]] 选择点还是不点
点向上k个x[i],不点下降y[i],
100%分 f[i][j] = min: f[i-1][j+y[i]], min (f[i-1][j-x[i]] ,f[i][j-x[i]] )
但是多加了个k会超时。我们可以想到将点击多次转化为一个完全背包,那么就可以从1扫到m,转化为f[i][j-x[i]]
注意处理跳超m,水管直接处理成设置不能到达的地方设成dp[i][j]=inf就好。
这样我们就将题目上升处理成了完全背包,下降处理为了01背包。
Intersting!来玩啊! 游戏传送门:http://www.newuser.top/2018/03/31/%E3%80%90%E6%9C%89%E8%B6%A3%E3%80%91%E9%A3%9E%E6%89%AC%E7%9A%84%E5%B0%8F%E9%B8%9F/
#include<bits/stdc++.h> using namespace std; const int inf = 0x3f3f3f3f; const int iii = 1000000000; int n,m,k; int x[10005],y[10005],low[10005],high[10005],youg[10005]; int dp[10005][2005]; int main() { scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=n;i++) { scanf("%d%d",&x[i],&y[i]); high[i]=m; low[i]=1; } int a,b,c; for(int i=1;i<=k;i++) { scanf("%d%d%d",&a,&b,&c); youg[a]=1; low[a]=b+1; high[a]=c-1; } memset(dp,inf,sizeof dp); for(int i=0;i<=m;i++) dp[0][i]=0; for(int i=1;i<=n;i++) { for(int j=x[i]+1;j<=m+x[i];j++) { dp[i][j]=min(dp[i-1][j-x[i]]+1,dp[i][j-x[i]]+1); } for(int j=m+1;j<=m+x[i];j++) dp[i][m]=min(dp[i][j],dp[i][m]); for(int j=m-y[i];j>=1;j--) { dp[i][j]=min(dp[i][j],dp[i-1][j+y[i]]); } for(int j=0;j<low[i];j++) dp[i][j]=inf; for(int j=m;j>high[i];j--) dp[i][j]=inf; } int ans=inf; for(int i=low[n];i<=high[n];i++) ans=min(ans,dp[n][i]); if(ans<iii){ printf("1\n%d",ans); return 0; } else printf("0\n"); ans=0; int kk; for(int i=1;i<=n;i++) { kk=1; for(int j=low[i];j<=high[i];j++) { if(dp[i][j]<iii) { kk=0; break; } } if(kk==1) { printf("%d",ans); return 0; } if(youg[i]==1) ans++; } }