【noip2013】【提高组】【Day2】【解题报告】

来源:互联网 发布:淘宝加入购物车怎么买 编辑:程序博客网 时间:2024/05/18 01:16

T1:积木大赛

题目链接:http://codevs.cn/problem/3288/

题解:可以发现如果后面一个格子比前面一个格子高,那么高出来的那块一定要单独处理。

         所以只要把后一个积木和前一个积木的高度差累加进答案再加上第一块积木的高度即可。

         复杂度O(n);

代码:

#include<iostream>#include<cstdio>#define N 100010using namespace std;int h[N],ans,minn(99999999),s[N],n;int main(){  scanf("%d",&n);  for (int i=1;i<=n;i++) {scanf("%d",&h[i]);}  for (int i=1;i<=n;i++){    if (h[i]>h[i-1]) ans+=h[i]-h[i-1];  }  cout<<ans<<endl; }

T2:花匠

题目链接:http://codevs.cn/problem/3289/

题解:首先O(n^2)的dp还是很简单的

         设f[i][1]表示到i结束,最后两盆花之间的趋势是上升的最大长度。

             f[i][0]表示到i结束,最后两盆花之间的趋势是下降的最大长度。

         显然

               f[i][1]=max(f[j][0]+1,f[i][1])(h[j]<h[i]);

               f[i][0]=max(f[j][1]+1,f[i][0])(h[j]>h[i]);

        因为是取最大值,所以我们用树状数组优化一下就可以通过了。

        复杂度O(n*logn)

代码:

#include<iostream>#include<cstdio>#define N 100010using namespace std;int f[N][2],h[N],ans,n,c1[N*10],c2[N*10],maxx;void add(int c[],int x,int v){for (int i=x;i<=maxx+1;i+=(i&(-i))) c[i]=max(c[i],v);}int query(int c[],int x){  int ans(0);for (int i=x;i;i-=(i&(-i))) ans=max(ans,c[i]);  return ans;}int main(){  scanf("%d",&n);  for (int i=1;i<=n;i++) {scanf("%d",&h[i]);maxx=max(maxx,++h[i]);}   maxx++;add(c1,h[1],1);add(c2,maxx-h[1],1);  for (int i=2;i<=n;i++){  f[i][1]=query(c1,h[i]-1)+1;f[i][0]=query(c2,maxx-h[i]-1)+1;          add(c2,maxx-h[i],f[i][1]);add(c1,h[i],f[i][0]);  ans=max(ans,max(f[i][1],f[i][0]));  } cout<<ans<<endl;} 

T3:华容道

题目链接:http://codevs.cn/problem/3290/

题解:这个题还是比较麻烦的。

            首先暴力bfs就可以通过前60%的数据.

            对于100%的数据。

            我们预处理一下p[x][y][k][h]表示当前格子在(x,y),空白格子在和它相邻的k方向,当前格子要往h方向移动1格的最小步数。

            这个东西显然可以广搜.复杂度O(n^4);

            然后我们把[x][y][k]作为状态,首先把空白格子bfs到起始格子的上下左右四个方向作为初始状态。

            考虑跑最短路。状态[x][y][k]显然可以更新到[x+dx[i]][y+dy[i]][k'],k'是i的反向。

            设目标格子为(tx,ty),

            最后答案在[tx][ty][0],[tx][ty][1],[tx][ty][2],[tx][ty][3]中取最小值即可.

            最终复杂度O(n^4+k*n^2)

代码:

#include<iostream>#include<cstdio>#include<cstring>#define INF 707406378using namespace std;int n,m,q,ex,ey,sx,sy,tx,ty,map[50][50],p[50][50][5][5];int dx[4]={0,0,-1,1},dy[4]={-1,1,0,0},l[1000000][4],dis[50][50],d[50][50][4];bool f[50][50][5];int bfs(int x,int y,int xx,int yy){  if (!map[x][y]||!map[xx][yy]) return INF;   memset(dis,127/3,sizeof(dis));  int h=0,t=1;l[t][1]=x;l[t][2]=y;dis[x][y]=0;  while (h<t){    int a=l[++h][1],b=l[h][2];if (a==xx&&b==yy) return dis[a][b];for (int i=0;i<4;i++){   int aa=a+dx[i],bb=b+dy[i];   if (aa>0&&aa<=n&&bb>0&&bb<=m&&dis[aa][bb]==INF&&map[aa][bb]){      dis[aa][bb]=dis[a][b]+1;l[++t][1]=aa;l[t][2]=bb;   }}  }return INF;}int spfa(){  int h(0),t(0),ans(INF);memset(f,0,sizeof(f));  for (int i=0;i<=4;i++)if (d[sx][sy][i]!=INF){   l[++t][1]=sx;l[t][2]=sy;l[t][3]=i;   f[sx][sy][i]=true;   }  while (h<t){    int x=l[++h][1],y=l[h][2],k=l[h][3];f[x][y][k]=false;for (int i=0;i<4;i++)  if (d[x+dx[i]][y+dy[i]][i^1]>d[x][y][k]+p[x][y][k][i]+1&&map[x+dx[i]][y+dy[i]]){    d[x+dx[i]][y+dy[i]][i^1]=d[x][y][k]+p[x][y][k][i]+1;    if (!f[x+dx[i]][y+dy[i]][i^1]){       l[++t][1]=x+dx[i];l[t][2]=y+dy[i];l[t][3]=i^1;   f[x+dx[i]][y+dy[i]][i^1]=true;     }  }   }  for (int i=0;i<4;i++) ans=min(ans,d[tx][ty][i]);  if (ans==INF) return -1;else return ans;}void cal(int ex,int ey,int sx,int sy,int tx,int ty){  if (!map[ex][ey]||!map[sx][sy]||!map[tx][ty]) {printf("-1\n");return;};  if (sx==tx&&sy==ty){printf("0\n");return;}  memset(d,127/3,sizeof(d));map[sx][sy]=0;  for (int i=0;i<4;i++) d[sx][sy][i]=bfs(ex,ey,sx+dx[i],sy+dy[i]);  map[sx][sy]=1;printf("%d\n",spfa());}void pre(){  for (int i=1;i<=n;i++)    for (int j=1;j<=m;j++){      int t=map[i][j];map[i][j]=0;      for (int k=0;k<4;k++)       for (int h=0;h<4;h++)          p[i][j][k][h]=bfs(i+dx[k],j+dy[k],i+dx[h],j+dy[h]);  map[i][j]=t;     }}int main(){  scanf("%d%d%d",&n,&m,&q);  for (int i=1;i<=n;i++)   for (int j=1;j<=m;j++)     scanf("%d",&map[i][j]);  pre();  for (int i=1;i<=q;i++){   scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty);cal(ex,ey,sx,sy,tx,ty);   }} 



        

0 0