1. 程式人生 > >NOIP2013 DAY2題解

NOIP2013 DAY2題解

-c med sed tar cnblogs http push printf ati

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\n",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\n",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\n",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\n");
            continue;
        }
        dfs(ex,ey,sx,sy,tx,ty,0,0,0); 
        if(ans==inf)printf("-1\n");
        else printf("%d\n",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\n",ans);
        else printf("-1\n");
    }
    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\n");
            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\n",ans);
    }
    return 0;
}
AC

NOIP2013 DAY2題解