NOIP2013 DAY2题解
Posted 小时のblog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\n",ans); fclose(stdin);fclose(stdout); return 0; }
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; }
这不跟昨天湖南的题一样么。
对于 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; }
一个多月前我做的...似乎是看了就是看了题解...
#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; }
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; }
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; }
正解..搜索+最短路。傻逼错误毁我青春...从下午写到现在...
我还是单独开个随笔讲这个题吧。邪王真眼
#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; }
以上是关于NOIP2013 DAY2题解的主要内容,如果未能解决你的问题,请参考以下文章
tyvj NOIP2017金秋冲刺训练营杯联赛模拟大奖赛第一轮Day2题解