【NOIP2014提高组】飞扬的小鸟

题目传送门:https://www.luogu.org/problem/show?pid=1941

不难看出,此题为动态规划。

我们用$f[i][j]$表示从第一行到达第i行第j列时点击屏幕的最少次数。

不难推出,$f[i][j]=min(f[i-1][j+y[i-1]],f[i-1][j-k*x[i-1]]+k)$,其中k为整数,且$j+y[i-1]$,$j-k*x[i-1]$需在合法范围内,$(i,j)$不能是柱子。

显然,这个转移的时间复杂度是$O(n*m^2)$的,只有70分,下面考虑进行优化。

先考虑只向上跳的情况,对于转移$f[i][j]=f[i-1][j-2x[i-1]+2$,我们不妨设$f[i][1..j]和f[1..i][1..m]$已经全部是最优解,那么在考虑$f[i][j]$时,只需要判断$f[i-1][j-x[i-1]$和$f[i][j-x[i-1]$哪个更优即可。

对于每一列,处理完向上跳的情况后,再处理向下滑行的状态。(我这里写挫了只剩下75,只能说数据实在太水)

PS:对于鸟贴顶的情况,需要特殊判断。

这样时间复杂度为$O(n*m)$。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define M 10100
 5 using namespace std;
 6 int f[M][1010]={0},b[M][1010]={0},n,m,k;
 7 int x[M]={0},y[M]={0};
 8 
 9 int get(int x,int y){
10     if(y<=0) return f[0][0];
11     if(y>m) return f[0][0];
12     return f[x][y];
13 }
14 
15 int main(){
16     scanf("%d%d%d",&n,&m,&k);
17     for(int i=0;i<n;i++) scanf("%d%d",x+i,y+i);
18     for(int i=1;i<=k;i++){
19         int p,l,h; scanf("%d%d%d",&p,&l,&h);
20         for(int ii=h;ii<=m;ii++) b[p][ii]=i;
21         for(int ii=0;ii<=l;ii++) b[p][ii]=i;
22     }
23     memset(f,1,sizeof(f)); 
24     for(int i=1;i<=m;i++) f[0][i]=0;
25     for(int i=1;i<=n;i++){
26         for(int j=1;j<=m;j++){
27             f[i][j]=min(f[i][j],get(i-1,j-x[i-1])+1);
28         }
29         for(int j=1;j<=m;j++)
30             f[i][j]=min(f[i][j],get(i,j-x[i-1])+1);
31         for(int j=m;j>=m-x[i-1];j--){
32             f[i][m]=min(f[i][m],f[i-1][j]+1);
33             f[i][m]=min(f[i][m],f[i][j]+1);
34         }
35             
36         for(int j=1;j<=m;j++)
37             f[i][j]=min(f[i][j],get(i-1,j+y[i-1]));
38         for(int j=1;j<=m;j++) if(b[i][j])
39         f[i][j]=f[0][0];
40     }
41     int minn=f[0][0];
42     for(int i=1;i<=m;i++) minn=min(minn,f[n][i]);
43     if(minn!=f[0][0]){
44         printf("1
%d
",minn);
45         return 0;
46     }
47     for(int i=n-1;i>=0;i--){
48         for(int j=1;j<=m;j++) if(f[i][j]!=f[0][0]){
49             int ans=0;
50             for(int ii=1;ii<=i;ii++) if(b[ii][m]) ans++;
51             printf("0
%d
",ans);
52             return 0;
53         }
54     }
55 }
原文地址:https://www.cnblogs.com/xiefengze1/p/7751053.html