P1941 [NOIP2014 提高组] 飞扬的小鸟

每一个x横坐标 可以点击多次 效果叠加 但哟避开 障碍
》状态更新-> dp dp[x][y][p] 当前坐标 x y 上一个坐标 转移过来 不点 0/点击 1
1.p=1 dp[x][y][1]=min(dp[x-1][y-up[i-1]][0/1],dp[x][ y-up[x-1] ][1])
2.p=0 dp[x][y][0]=min(dp[x-1][y+down[x-1]][0/1],dp[x][y][0])
优化 [p]->很明显每次选取都是在p=0or1p=0or1中选取最小值,那么可以滚动数组去掉p数组,上状态转移方程其他不变。
memset(dp,0x3f) dp[0][1~n]=0(从>=1出发) dp[x][1~low]=inf,dp[x][up~n]=inf
若过不了 int i,j; for(i=n;i>=1;i--) { for(j=1;j<=m;++j) { if(f[i][j]<f[0][0]) break; } if(j<=m) break; } ans=0; for(int j=1;j<=i;++j) { if(e[j]) ans++; } printf("0\n%d\n",ans);
》up 完全背包 down 0/1背包
》[x]只与上一个状态有关 i%2 i%2^1(i-1%2)
#include<bits/stdc++.h> using namespace std; #define int int #define gc(a) a=getchar() #define pc(a) putchar(a) int read(){ char c;int x=0;bool flag=0;c=getchar(); while(c<'0'||c>'9'){if(c=='-') flag=1;c=getchar();} while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48),c=getchar();} return flag?-x:x; } void pr(int x){ if(x<0){x=-x;putchar('-');} if(x>9) pr(x/10); putchar(x%10+48); } //-------快读------ #define inf 0x3f3f3f3f const int maxn=10005; const int maxm=10005; struct node { int id,h,l; bool operator <(const node &a) const { return id<a.id; } }o[maxn]; int x[maxn],y[maxn],dp[2][maxm],n,m,k,cnt=1,ans; int main() { memset(dp,inf,sizeof(dp));//两个被遗忘的初始化之一qwq n=read(),m=read(),k=read(); for(int i=1;i<=n;i++) x[i]=read(),y[i]=read(); for(int i=1;i<=k;i++) o[i].id=read(),o[i].l=read(),o[i].h=read(); sort(o+1,o+k+1);//管道id排序! for(int i=1;i<=m;i++) dp[0][i]=0; for(int i=1;i<=n;i++) { for(int j=0;j<=m;j++)//注意要初始化! dp[i%2][j]=inf; for(int j=x[i]+1;j<=x[i]+m;j++)//p=1,完全背包 dp[i%2][j]=min(dp[i%2^1][j-x[i]]+1,dp[i%2][j-x[i]]+1); for(int j=m+1;j<=x[i]+m;j++)//比m大的都是m dp[i%2][m]=min(dp[i%2][m],dp[i%2][j]); for(int j=1;j<=m-y[i];j++)//p=0,01背包 dp[i%2][j]=min(dp[i%2][j],dp[i%2^1][j+y[i]]); if(i==o[cnt].id)//如果这个地方有管道 { ans=inf;//主要每次都要初始化一次! for(int j=0;j<=o[cnt].l;j++) dp[i%2][j]=inf; for(int j=o[cnt].h;j<=m;j++) dp[i%2][j]=inf; for(int j=1;j<=m;j++)//寻找是否可以通过 ans=min(dp[i%2][j],ans); if(ans==inf) { pr(0);putchar('\n');pr(cnt-1);return 0; } cnt++; } } ans=inf;//注意要初始化! for(int j=1;j<=m;j++) ans=min(dp[n%2][j],ans); pr(1);putchar('\n');pr(ans); return 0; } /* #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn=10000+10; const int maxm=2000+10; int n,m,p; int x[maxn],y[maxn]; //i位置,上升x[i],下降y[i] int low[maxn],high[maxn]; //i位置能通过的范围是low[i]-high[i] int f[maxn][maxm]; //到(i,j)的最少点击次数 bool e[maxn]; //e[i]表示i位置有没有管道 int main() { scanf("%d%d%d",&n,&m,&p); for(int i=1; i<=n; ++i) scanf("%d%d",&x[i],&y[i]); for(int i=1; i<=n; ++i) { low[i]=1; high[i]=m; } int a,b,c; for(int i=1; i<=p; ++i) { scanf("%d%d%d",&a,&b,&c); e[a]=1; low[a]=b+1; high[a]=c-1; } memset(f,0x3f,sizeof(f)); for(int i=1; i<=m; ++i) f[0][i]=0; for(int i=1; i<=n; ++i) { for(int j=x[i]+1; j<=m+x[i]; ++j) f[i][j]=min(f[i-1][j-x[i]]+1,f[i][j-x[i]]+1); for(int j=m+1; j<=m+x[i]; ++j) f[i][m]=min(f[i][m],f[i][j]); for(int j=1; j<=m-y[i]; ++j) f[i][j]=min(f[i][j],f[i-1][j+y[i]]); for(int j=1; j<low[i]; ++j) f[i][j]=f[0][0]; //不能通过(INF) for(int j=high[i]+1; j<=m; ++j) f[i][j]=f[0][0]; //不能通过(INF) } int ans=f[0][0]; for(int j=1;j<=m;++j) { ans=min(ans,f[n][j]); } if(ans<f[0][0]) printf("1\n%d\n",ans); else{ int i,j; for(i=n;i>=1;i--) { for(j=1;j<=m;++j) { if(f[i][j]<f[0][0]) break; } if(j<=m) break; } ans=0; for(int j=1;j<=i;++j) { if(e[j]) ans++; } printf("0\n%d\n",ans); } return 0; } */

浙公网安备 33010602011771号