NOIP2011复赛提高组day1(A:铺地毯 B:选择客栈 C:mayan游戏)

来源:互联网 发布:centos7 开放3306端口 编辑:程序博客网 时间:2024/05/17 01:00

话说这应该算是比较简单的一届NOIP
但是博主第三题智障了一下 其实是因为我是弱鸡
只得了20分 0.0
❤都在滴血。。
30分无脑代码x,y输反了。
BFS(我心中的AC代码)WA(没剪枝导致循环队列都开不下Memory)+RE(博主逗比)
于是打到220的酱油成为机房倒数第一。。。
555

于是进入正题
A题:
这题简直水到爆炸
应该没人写不出来
只有一组判断数据,直接判就好了。。

#include<bits/stdc++.h>using namespace std;#define M 10005int a[M],b[M],dx[M],dy[M];int main(){    int n;    scanf("%d",&n);    for(int i=1;i<=n;i++)scanf("%d %d %d %d",&a[i],&b[i],&dx[i],&dy[i]);    int x,y;    scanf("%d %d",&x,&y);    int ans=-1;    for(int i=1;i<=n;i++)        if(x>=a[i]&&x<=a[i]+dx[i]&&y>=b[i]&&y<=b[i]+dy[i])            ans=i;    printf("%d\n",ans);    return 0;}

B题:
这题有很多解法,都十分漂亮:
比如:
分治:严格O(n*logn)
尺取:O(n*k)【优化后可达O(n)】
博主考试的时候敲得是O(n*k)的尺取法
于是讲解尺取法:
首先,我们知道若以两个相同颜色作为端点小区间满足条件
那么同样的大区间也满足
于是尺取法闪亮登场
可以把所有颜色相同的客栈push_back到vector中(方便,虽然有点慢)
每次对于一个左端点,找到一个最小的符合条件的右端点
于是乎,右边的所有端点都满足条件。。
于是乎累加吧。。。。

#include<bits/stdc++.h>using namespace std;#define M 200005#define LL long longvoid Rd(int &res){//数据大?不怕,读入挂带你走遍天下!!!    char c;res=0;    while(c=getchar(),!isdigit(c));    do res=(res<<3)+(res<<1)+(c^48);    while(c=getchar(),isdigit(c));}struct node{    int id,val;};int val[M];vector<node>Colr[M];int n,k,p;int main(){    scanf("%d %d %d",&n,&k,&p);    for(int i=1;i<=n;i++){        int col;node tmp;        Rd(col);Rd(tmp.val);        val[i]=tmp.val;        tmp.id=i;        Colr[col].push_back(tmp);    }LL ans=0;//原题并不需要long long,但小C把数据弄大了,只为卡掉某些可怜的孩纸10分    for(int i=0;i<k;i++){//不要被这么多层for吓到,其实也就O(n*k)        int m=Colr[i].size();        int l=0,r=0;        while(r<m){            bool f=true;            if(Colr[i][l].val<=p){                ans+=m-l-1;                l++;r++;                continue;            }while(f&&r<m-1){                for(int j=Colr[i][r].id+1;j<=Colr[i][r+1].id;j++)                    if(val[j]<=p){                        f=false;                        break;                    }                r++;            }if(f)break;            ans+=1ll*(m-r)*(r-l);            l=r;        }    }cout<<ans<<endl;    return 0;}

C题:
其实这是一道模拟题纯考验代码功底,
但是无论是BFS还是DFS,暴力的裸分都只有50~70分
于是需要剪枝,
这个剪枝其实也比较无脑,
我们可以知道的是
对于每一个i,j而言
如果a[i-1][j]位置上有方块,
那么是不需要和左边进行swap的(在[i-1][j]这个位置上已经进行过交换)
于是程序运行的时间减少了接近一半
至于暴力代码
BFS和DFS都行,
但是博主建议使用DFS
因为DFS不需要考虑递归爆栈的情况,内存很小
而BFS就算开循环队列也有点慌
而且BFS虽然和DFS的复杂度差不多
但是系数实在有点不敢恭维

DFS代码:

#include<bits/stdc++.h>using namespace std;#define M 10int n,mark[M][M],a[M][M],Ct,tp;struct node{    char a[5][8];    char x[6],y[6],g[6];};void down(int x,int y,int len,node &nxt){//交换之后方块不能悬空,于是需要down一下    for(int j=y;j<7;j++){        if(j+len<7&&nxt.a[x][j+len])            nxt.a[x][j]=nxt.a[x][j+len];        else nxt.a[x][j]=0;    }}int Puz(node &nxt){//消除方块    int res=0;tp++;    for(int i=0;i<5;i++)        for(int j=0;j<7&&nxt.a[i][j];j++){        //一次mark3个方块就够了,没必要全部mark,别的点之后遍历的时候回会ark到            if(i>0&&i<4&&nxt.a[i+1][j]==nxt.a[i][j]&&nxt.a[i-1][j]==nxt.a[i][j])                mark[i][j]=mark[i+1][j]=mark[i-1][j]=tp;//无需对mark数组进行memset,提高了效率            if(j>0&&j<6&&nxt.a[i][j+1]==nxt.a[i][j]&&nxt.a[i][j-1]==nxt.a[i][j])                mark[i][j]=mark[i][j+1]=mark[i][j-1]=tp;        }    for(int i=0;i<5;i++)        for(int j=0;j<7;j++)            if(mark[i][j]==tp){                nxt.a[i][j]=0;//消                res++;            }    for(int i=0;i<5;i++){        int pre,f=0;        for(int j=0;j<7;j++){            if(!f&&!nxt.a[i][j]){                pre=j;                f=1;            }if(f&&nxt.a[i][j]){                down(i,pre,j-pre,nxt);//down                break;            }        }    }if(res)res+=Puz(nxt);//再消    return res;}int Move(int x,int y,int k,node &nxt){    int tmp=nxt.a[x][y];    nxt.a[x][y]=nxt.a[x+k][y];    if(!nxt.a[x][y])//换进来的是空白块,需要down        down(x,y,1,nxt);    while(y>0&&!nxt.a[x+k][y-1])y--;    nxt.a[x+k][y]=tmp;    //找到x+k这一列中最低的空白点(或是[x+k][y]这个点【该点有方块时】),与[x][y]的值进行交换    return Puz(nxt);}void dfs(int c,int num,node tmp){    if(!num){//找到了答案,字典序一定最小        for(int i=1;i<=c;i++)            printf("%d %d %d\n",tmp.x[i],tmp.y[i],tmp.g[i]);        exit(0);    }if(c==n||num<3)return;//不满足,return    for(int i=0;i<5;i++)        for(int j=0;j<7&&tmp.a[i][j];j++){            int NUM;            node T;            if(i!=4){                T=tmp;                NUM=num-Move(i,j,1,T);//减去消除的方块                T.x[c+1]=i;//储存答案                T.y[c+1]=j;                T.g[c+1]=1;                dfs(c+1,NUM,T);//继续移动方块            }if(i&&!tmp.a[i-1][j]){                T=tmp;                NUM=num-Move(i,j,-1,T);                T.x[c+1]=i;                T.y[c+1]=j;                T.g[c+1]=-1;                dfs(c+1,NUM,T);            }        }}void solve(){    node tmp;    for(int i=0;i<5;i++)        for(int j=0;j<7;j++)            tmp.a[i][j]=a[i][j];    dfs(0,Ct,tmp);    puts("-1");//找不到满足的方案}int main(){    scanf("%d",&n);    for(int i=0;i<5;i++)        for(int j=0;j<8;j++){            scanf("%d",&a[i][j]);            if(a[i][j]==0)break;            else Ct++;//计算初始方块数        }    solve();    return 0;}

BFS代码(其实两份代码差不多):
这份BFS是博主在DFS的基础上改的

#include<bits/stdc++.h>using namespace std;#define M 10#define N 2400000int n,mark[M][M],a[M][M],Ct,tp;struct node{    char a[5][8];    char x[6],y[6],g[6];    char step,num;}Q[N];void down(int x,int y,int len,node &nxt){    for(int j=y;j<7;j++){        if(j+len<7&&nxt.a[x][j+len])            nxt.a[x][j]=nxt.a[x][j+len];        else nxt.a[x][j]=0;    }}int Puz(node &nxt){    int res=0;tp++;    for(int i=0;i<5;i++)        for(int j=0;j<7&&nxt.a[i][j];j++){            if(i>0&&i<4&&nxt.a[i+1][j]==nxt.a[i][j]&&nxt.a[i-1][j]==nxt.a[i][j])                mark[i][j]=mark[i+1][j]=mark[i-1][j]=tp;            if(j>0&&j<6&&nxt.a[i][j+1]==nxt.a[i][j]&&nxt.a[i][j-1]==nxt.a[i][j])                mark[i][j]=mark[i][j+1]=mark[i][j-1]=tp;        }    for(int i=0;i<5;i++)        for(int j=0;j<7;j++)            if(mark[i][j]==tp){                nxt.a[i][j]=0;                res++;            }    for(int i=0;i<5;i++){        int pre,f=0;        for(int j=0;j<7;j++){            if(!f&&!nxt.a[i][j]){                pre=j;                f=1;            }if(f&&nxt.a[i][j]){                down(i,pre,j-pre,nxt);                break;            }        }    }if(res)res+=Puz(nxt);    return res;}int Move(int x,int y,int k,node &nxt){    int tmp=nxt.a[x][y];    nxt.a[x][y]=nxt.a[x+k][y];    if(!nxt.a[x][y])        down(x,y,1,nxt);    while(y>0&&!nxt.a[x+k][y-1])y--;    nxt.a[x+k][y]=tmp;    return Puz(nxt);}//以上代码与DFS写法基本一模一样void BFS(int Tmp[M][M]){//BFS比DFS更无脑。。。    int l=0,r=0;    node tmp;    for(int i=0;i<5;i++)        for(int j=0;j<7;j++)            tmp.a[i][j]=Tmp[i][j];    tmp.num=Ct;    tmp.step=0;    Q[r++]=tmp;    while(l!=r){//使用循环队列,增大空间的利用率        tmp=Q[l];        l=(l+1)%N;        if(tmp.step==n)return;        for(int i=0;i<5;i++){            for(int j=0;j<7&&tmp.a[i][j];j++){                node nxt;                if(i!=4){                    nxt=tmp;                    nxt.step++;                    nxt.num-=Move(i,j,1,nxt);                    nxt.x[nxt.step]=i;                    nxt.y[nxt.step]=j;                    nxt.g[nxt.step]=1;                    if(!nxt.num){//消完了所有方块                        for(int k=1;k<=nxt.step;k++)                            printf("%d %d %d\n",nxt.x[k],nxt.y[k],nxt.g[k]);                        exit(0);                    }Q[r]=nxt;r=(r+1)%N;                }if(i&&!tmp.a[i-1][j]){//其实内部代码也基本一模一样                    nxt=tmp;                    nxt.step++;                    nxt.num-=Move(i,j,-1,nxt);                    nxt.x[nxt.step]=i;                    nxt.y[nxt.step]=j;                    nxt.g[nxt.step]=-1;                    if(!nxt.num){                        for(int k=1;k<=nxt.step;k++)                            printf("%d %d %d\n",nxt.x[k],nxt.y[k],nxt.g[k]);                        exit(0);                    }Q[r]=nxt;r=(r+1)%N;                }            }        }    }}void solve(){    BFS(a);    puts("-1");}int main(){    scanf("%d",&n);    for(int i=0;i<5;i++)        for(int j=0;j<8;j++){            scanf("%d",&a[i][j]);            if(a[i][j]==0)break;            else Ct++;        }    solve();    return 0;}

然而说的这么容易,考试的时候仍旧没敲出来。。。。

2 0
原创粉丝点击