NOIP2013 DAY2题解

DAY2 

T1积木大赛

传送门

题目大意:每次可以选区间[l,r]加1,最少选几次,让每个位置有

它应有的高度。

题解:O(n)扫一遍就好了。后一个比前一个的高度低,那么前一个已经把它覆盖了,

如果高那么就需要+1了。

代码:

#include<iostream>
#include<cstdio>
#define maxn 100009
using namespace std;

int n,x,pre,ans;

void read(int &x){
    char ch=getchar();int f=1;x=0;
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    x*=f;
}

int main(){
    freopen("block.in","r",stdin);
    freopen("block.out","w",stdout);
    read(n);
    for(int i=1;i<=n;i++){
        read(x);
        if(x>pre)ans=ans+x-pre;
        pre=x;
    }
    printf("%d
",ans);
    fclose(stdin);fclose(stdout);
    return 0;
}
AC

T2花匠

传送门

题目大意:求最长波动子序列

题解:贪心

暴力dp[i][1/0][1/0]表示到第i个数作为波峰(1)或波谷(0)选(1)还是不选(0)的最长长度

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 100008
using namespace std;

int n,h[maxn],dp[maxn][2][2];

void read(int &x){
    char ch=getchar();x=0;int f=1;
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    x=x*f;
}

int main(){
    read(n);
    for(int i=1;i<=n;i++)read(h[i]);
    dp[1][1][1]=dp[1][0][1]=1;
    for(int i=2;i<=n;i++){
        for(int j=1;j<i;j++){
            if(h[i]>h[j])dp[i][1][1]=max(dp[i][1][1],dp[j][0][1]+1);
            if(h[i]<h[j])dp[i][0][1]=max(dp[i][0][1],dp[j][1][1]+1);
            dp[i][0][0]=dp[i][1][0]=max(max(dp[j][0][1],dp[j][0][0]),max(dp[j][1][0],dp[j][1][1]));
        }
    }
    printf("%d
",max(max(dp[n][1][1],dp[n][1][0]),max(dp[n][0][1],dp[n][0][0])));
    return 0;
}
70

这不跟昨天湖南的题一样么。

对于 5 4 3 2 9

5 2 9,4 2 9,3 2 9,好像没什么区别。那么连续递减的5 4 3 2就可以看成一个数了。

以一个数为大的和小的分别扫一遍就好。

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 100008
using namespace std;

int ans,ret,cur,flag,n,h[maxn];

void read(int &x){
    char ch=getchar();x=0;int f=1;
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    x=x*f;
}

int main(){
    freopen("flower.in","r",stdin);
    freopen("flower.out","w",stdout);
    read(n);
    for(int i=1;i<=n;i++)read(h[i]);
    cur=h[1];ans=1;
    for(int i=2;i<=n;i++){
        if(flag){
            if(h[i]<cur)flag=0,ans++,cur=h[i];
            else cur=max(cur,h[i]);
        }else{
            if(h[i]>cur)flag=1,ans++,cur=h[i];
            else cur=min(cur,h[i]);
        }
    }
    cur=h[1];ret=1;flag=0;
    for(int i=2;i<=n;i++){
        if(flag){
            if(h[i]>cur)flag=0,ret++,cur=h[i];
            else cur=min(cur,h[i]);
        }else{
            if(h[i]<cur)flag=1,ret++,cur=h[i];
            else cur=max(cur,h[i]);
        }
    }
    ans=max(ans,ret);
    printf("%d
",ans);
    fclose(stdin);fclose(stdout);
    return 0;
}
AC

一个多月前我做的...似乎是看了就是看了题解...

#include<iostream>
#include<cstdio>
using namespace std;
int n,pre,now,r=1,d=1;
int main()
{
    scanf("%d",&n);
    scanf("%d",&pre);//当前这盆花前面那盆花的高度,初始为第一盆花的高度。 
    for(int i=1;i<n;i++)
    {
        scanf("%d",&now);
        if(now>pre)r=max(r,d+1);//当前这盆花高度大于前面那盆花高度 
        if(now<pre)d=max(d,r+1);//说明现在是上升序列,就要求出到Now这个花盆且波动为 
        pre=now;             //上升的最优解,就从原来求出的最后波动为上升的最优解,
    }                       //(也就是说此时当前这盆花不加入之前最优解,移走)
    printf("%d",max(r,d));//和从最后波动为下降的最优解+1选取最优值(不移走)。
    return 0;
}
AC

T3华容道

传送门

题目大意:一个n*m的矩阵,有n*m-1个棋子。1表示该棋子能移动,0表示不能。

给出指定位置和目标位置。求最少几步能利用空白格子将指定位置棋子移到目标位置。

题解:

dfs 5分...怀疑人生

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define inf 100000000
using namespace std;

int n,m,q,x,cnt,ans;
int ex,ey,sx,sy,tx,ty;
int t[40][40],tmp[40][40],vis[40][40];
int mx[4]={0,1,-1,0},
    my[4]={-1,0,0,1};

void read(int &x){
    char ch=getchar();x=0;int f=1;
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    x=x*f;
}

void dfs(int ex,int ey,int sx,int sy,int tx,int ty,int prex,int prey,int ste){
    if(ex==tx&&ey==ty&&abs(sx-ex)+abs(sy-ey)<=1){
        ans=min(ans,ste+1);
        return;
    }
    for(int i=0;i<4;i++){
        int xx=ex+mx[i],yy=ey+my[i];
        if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&t[xx][yy]&&(xx!=prex||yy!=prey)&&!vis[xx][yy]){
            vis[xx][yy]=true;
            if(xx==sx&&yy==sy){
                dfs(xx,yy,ex,ey,tx,ty,ex,ey,ste+1);
            }else dfs(xx,yy,sx,sy,tx,ty,ex,ey,ste+1);
        }
    }
}

int main(){
//    freopen("puzzle.in","r",stdin);
//    freopen("puzzle.out","w",stdout);
    read(n);read(m);read(q);
    for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++)
      read(t[i][j]);
    for(int i=1;i<=q;i++){
        cnt=0;ans=inf;
        memset(vis,0,sizeof(vis));
        read(ex);read(ey);//空白格子 
        vis[ex][ey]=true;
        read(sx);read(sy);//指定棋子 
        read(tx);read(ty);//目标位置
        if(sx==tx&&sy==ty){
            printf("0
");
            continue;
        }
        dfs(ex,ey,sx,sy,tx,ty,0,0,0); 
        if(ans==inf)printf("-1
");
        else printf("%d
",ans);
    }
//    fclose(stdin);fclose(stdout);
    return 0;
}
5

bfs 70 其实考试时开始写的bfs。发现不会记录状态。

看了题解算来只需要记录空白格子和指定棋子的位置就好了。

时间复杂度O(q*(nm)^2)

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;

int ans,n,m,qx,tx,ty;
int t[40][40],vis[40][40][40][40];
int mx[4]={0,1,0,-1},
    my[4]={-1,0,1,0};
struct Node{
    int ex,ey,sx,sy,ste;
}now;
queue<Node>q;

void read(int &x){
    char ch=getchar();x=0;int f=1;
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    x=x*f;
}

void BFS(){
    memset(vis,0,sizeof(vis));
    Node tmp,cur;
    vis[now.sx][now.sy][now.ex][now.ey]=true;
    while(!q.empty())q.pop();q.push(now);
    while(!q.empty()){
        cur=q.front();q.pop();
        if(cur.sx==tx&&cur.sy==ty){
            ans=cur.ste;
            return;
        }
        for(int i=0;i<4;i++){
            tmp=cur;
            int xx=tmp.ex+mx[i],yy=tmp.ey+my[i];
            if(!t[xx][yy]||xx<1||xx>n||yy<1||yy>m)continue;
            if(xx==tmp.sx&&yy==tmp.sy)tmp.sx=tmp.ex,tmp.sy=tmp.ey;
            tmp.ex=xx;tmp.ey=yy;tmp.ste=cur.ste+1;
            if(!vis[tmp.sx][tmp.sy][tmp.ex][tmp.ey]){
                vis[tmp.sx][tmp.sy][tmp.ex][tmp.ey]=true;
                q.push(tmp);
            }
        }
    }
}

int main(){
    read(n);read(m);read(qx);
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) read(t[i][j]);
    for(;qx;qx--){
        read(now.ex);read(now.ey);read(now.sx);read(now.sy);read(tx);read(ty);
        now.ste=0;ans=n*m;
        BFS();
        if(ans!=n*m)printf("%d
",ans);
        else printf("-1
");
    }
    return 0;
}
70

正解..搜索+最短路。傻逼错误毁我青春...从下午写到现在...

我还是单独开个随笔讲这个题吧。邪王真眼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define maxn 5000
#define inf 2147483647

int n,m,qx,sumedge,ans,ex,ey,sx,sy,tx,ty,p;
int map[40][40],pre_dis[40][40],head[maxn],vis[maxn],dis[maxn];
int mx[4]={-1,0,1,0},
    my[4]={0,1,0,-1};
struct Node{
    int x,y;
}cur,nxt;
queue<Node>q;
queue<int>qn;

struct Edge{
    int x,y,z,nxt;
    Edge(int x=0,int y=0,int z=0,int nxt=0):
        x(x),y(y),z(z),nxt(nxt){}
}edge[maxn];

void add(int x,int y,int z){
    edge[++sumedge]=Edge(x,y,z,head[x]);
    head[x]=sumedge;
}

int get_id(int i,int j){
    return (i-1)*m*4+(j-1)*4;
}

void bfs(int ex,int ey,int sx,int sy,int d){
    memset(pre_dis,-1,sizeof(pre_dis));
    pre_dis[ex][ey]=0;pre_dis[sx][sy]=1;
    Node now,nxt;now.x=ex;now.y=ey;
    while(!q.empty())q.pop();
    q.push(now);
    while(!q.empty()){
        now=q.front();q.pop();
        int x=now.x,y=now.y;
        for(int i=0;i<4;i++){
            int xx=x+mx[i],yy=y+my[i];
            if(xx<1||xx>n||yy<1||yy>m||!map[xx][yy]||pre_dis[xx][yy]!=-1)continue;
            pre_dis[xx][yy]=pre_dis[x][y]+1;
            nxt.x=xx;nxt.y=yy;
            q.push(nxt);    
        }
    }
    if(d==4)return;
    int id=get_id(sx,sy);
    for(int i=0;i<4;i++)
     if(pre_dis[sx+mx[i]][sy+my[i]]>0)
       add(id+d,id+i,pre_dis[sx+mx[i]][sy+my[i]]);
    add(id+d,get_id(ex,ey)+(d+2)%4,1);
}

void spfa(int sx,int sy){
    memset(dis,-1,sizeof(dis));
    memset(vis,0,sizeof(vis));
    while(!qn.empty())qn.pop();
    int id=get_id(sx,sy);
    for(int i=0;i<4;i++)
        if(pre_dis[sx+mx[i]][sy+my[i]]!=-1){
            dis[id+i]=pre_dis[sx+mx[i]][sy+my[i]];
            qn.push(id+i);
        } 
    while(!qn.empty()){
        int cur=qn.front();qn.pop();vis[cur]=false;
        for(int i=head[cur];i;i=edge[i].nxt){
            int v=edge[i].y;
            if(dis[v]>dis[cur]+edge[i].z||dis[v]==-1){
                dis[v]=dis[cur]+edge[i].z;
                if(!vis[v]){
                    vis[v]=true;
                    qn.push(v);
                }
            }
        }
    }
}

int main(){
    scanf("%d%d%d",&n,&m,&qx);
    for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++)
      scanf("%d",&map[i][j]);
    for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++)
      if(map[i][j]){
          if(map[i-1][j])bfs(i-1,j,i,j,0);
          if(map[i][j+1])bfs(i,j+1,i,j,1);
          if(map[i+1][j])bfs(i+1,j,i,j,2);
          if(map[i][j-1])bfs(i,j-1,i,j,3);
      }
    for(int i=1;i<=qx;i++){
        scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty);
        if(sx==tx&&sy==ty){
            printf("0
");
            continue;
        }
        bfs(ex,ey,sx,sy,4);
        ans=inf;
        spfa(sx,sy);
        int id=get_id(tx,ty);
        for(int j=0;j<4;j++)
         if(dis[id+j]!=-1)ans=min(ans,dis[id+j]);
        if(ans==inf) ans=-1;
        printf("%d
",ans);
    }
    return 0;
}
AC
原文地址:https://www.cnblogs.com/zzyh/p/7686050.html