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;}
然而说的这么容易,考试的时候仍旧没敲出来。。。。
- NOIP2011复赛提高组day1(A:铺地毯 B:选择客栈 C:mayan游戏)
- [NOIP2011] day1铺地毯,选择客栈,Mayan游戏
- NOIP2011 铺地毯 选择客栈 Mayan游戏
- NOIP2011(DAY1)解题报告(C/C++)(铺地毯)(选择客栈)(Mayan 游戏)
- NOIP2011 提高组 复赛 day1 mayan mayan游戏
- NOIP2011 提高组 复赛 day1 hotel 选择客栈
- NOIP2011复赛(day1):选择客栈
- NOIP2011 提高组 复赛 day1 carpet 铺地毯
- Noip 2011 解题报告 Day1 (铺地毯,选择客栈,Mayan 游戏)
- 【搜索】【NOIP2011提高组Day1】Mayan游戏
- 选择客栈 NOIP2011 提高组 Day1 T2
- NOIP 2011 题解 铺地毯 选择客栈 Mayan 游戏
- 【模拟】【NOIP2011提高组Day1】铺地毯
- NOIP 2011 DAY 1 解题报告(铺地毯,选择客栈,mayan游戏)
- NOIP2013复赛提高组day1(A:转圈游戏 B:火柴排队 C:货车运输)
- 【枚举+优化】【NOIP2011提高组Day1】选择客栈
- NOIP2011提高组-Mayan游戏
- NOIP2011提高组day1第1题-铺地毯题解
- Jdk 1.7.0_17中提供的默认的排序算法
- C字符串操作:查找字符串函数strstr()
- ORACLE wm_concat
- 第9周项目4 -广义表算法库及应用(2)
- LeetCode [416. Partition Equal Subset Sum] 难度[medium]
- NOIP2011复赛提高组day1(A:铺地毯 B:选择客栈 C:mayan游戏)
- 诛仙有感
- Android基础之handler使用步骤
- dijkstra算法求最短路径
- ui.qml 进入qmljs文本编辑模式
- SSM+EasayUI实现省市二级联动
- 用原生js写出类似于ajax请求程序
- 近期的学习计划_2016
- idea clojure 删除 括号的问题