Noip 提高组 Day2 解题报告.docx
- 文档编号:3573349
- 上传时间:2022-11-24
- 格式:DOCX
- 页数:11
- 大小:19.42KB
Noip 提高组 Day2 解题报告.docx
《Noip 提高组 Day2 解题报告.docx》由会员分享,可在线阅读,更多相关《Noip 提高组 Day2 解题报告.docx(11页珍藏版)》请在冰豆网上搜索。
Noip提高组Day2解题报告
Noip2013Day2解题报告
--ByGreenCloudS
第一题:
积木大赛 (模拟)
直接贪心,每次取最大一个连续区间,然后模拟即可。
令h[0]=0,答案就是:
∑h[i]-h[i-1](0h[i-1])
复杂度:
O(n)
代码1(Cpp):
#include
#defineMAXN100010
inth[MAXN],ans=0,n;
intmain(){
h[0]=0;
scanf("%d",&n);
for(inti=0;i++ scanf("%d",&h[i]); if(h[i]>h[i-1])ans+=h[i]-h[i-1]; } printf("%d\n",ans); return0; } 代码2(先对高度进行基数排序,然后逐行计算区间数,复杂度也是O(n))(Cpp): #include #include usingnamespacestd; #defineMAXH10010 #defineMAXN100010 structnode{ node*next; intt; node(){ next=NULL; } }*head[MAXH]; intmaxh=0; voidInsert(inth,intt){ maxh=max(maxh,h); node*p=new(node); p->t=t,p->next=head[h]; head[h]=p; } intn,h,delta=1,ans=0; boolf[MAXN]; intmain(){ memset(f,true,sizeof(f)),memset(head,0,sizeof(head)); cin>>n; f[0]=f[n+1]=false; for(inti=0;i++ for(inti=0;i<=maxh;i++){ if(i)ans+=delta; for(node*p=head[i];p;p=p->next){ if(f[p->t-1]&&f[p->t+1])delta++; if((! f[p->t-1])&&(! f[p->t+1]))delta--; f[p->t]=false; } } cout< return0; } 第二题: 花匠(动态规划) 这道题明显可以用类似最长上升子序列的动态规划求解,易得思路如下: 用f(i,0)表示以i为结尾的且最后一段上升的子序列最大长度,f(i,1)表示表示以i为结尾的且最后一段下降的子序列最大长度,那么答案明显就是max{f(i,0),f(i,1)} 方程: f(i,0)=max{f(j,1)}+10<=j f(i,1)=max{f(j,0)}+10<=jh[i] 边界: f(0,0)=f(0,1)=0 如果直接DP毫无疑问复杂度是O(n^2),会TLE,但是,考虑到我们每次取最值时候取得都是一个区间里的数,如f(i,0)=max{f(j,1)}+10<=j 这道题还有一个解法,直接求拐点数目,然后就可以神奇的做到O(n)了,由于我找不到满意的证明,就不发上来了。 代码(DP+BIT)(Cpp): #include #include #include usingnamespacestd; #defineMAXN100010 #definelowbit(x)(((~(x))+1)&x) #defineMAXH1000010 #defineFor(i,x)for(inti=x;i;i-=lowbit(i)) #definerep(i,x)for(inti=x;i<=maxh;i+=lowbit(i)) intt0[MAXH],t1[MAXH]; inth[MAXN],n,maxh=0; intf[MAXN][2],ans=0; voidAdd0(intx,inty){ rep(i,x)t0[i]=max(t0[i],y); } voidAdd1(intx,inty){ rep(i,x)t1[i]=max(t1[i],y); } intMax0(intx){ intrec=0; For(i,x)rec=max(rec,t0[i]); returnrec; } intMax1(intx){ intrec=0; For(i,x)rec=max(rec,t1[i]); returnrec; } intmain(){ scanf("%d",&n); for(inti=0;i++ scanf("%d",&h[i]); maxh=max(maxh,++h[i]); f[i][0]=f[i][1]=1; } maxh++; memset(t0,0,sizeof(t0)),memset(t1,0,sizeof(t1)); for(inti=0;i++ f[i][0]=max(Max0(h[i]-1)+1,f[i][0]); f[i][1]=max(Max1(maxh-h[i]-1)+1,f[i][1]); Add0(h[i],f[i][1]),Add1(maxh-h[i],f[i][0]); ans=max(ans,max(f[i][0],f[i][1])); } printf("%d\n",ans); return0; } 第三题: 华容道 (最短路) 这道题的数据范围是n<=30,所以,我们可以看到,裸的O(n^4)的BFS对于求解q较小的情况是无压力的,但是在q大的情况下,毫无疑问会TLE,明显,在q较大的情况下,我们需要将每次BFS中重复搜索的冗余信息除去,所以我们可以先分析题目性质: (这里称要移动的棋子为目标棋子) 首先,如果要移动目标棋子,那么我们首先必须要将空格移到该棋子的上下左右四个方向上相邻位置之一,然后才可以移动该棋子。 然后,我们分析该棋子移动时候的性质: 棋子每次可以移动,仅当空格位于其相邻位置的时候,每次移动完棋子,空格总会在棋子相邻的位置,那么我们发现,对于棋子在某一位置,然后空格又在其四个方向上某一相邻位置时,棋子要想某一方向移动一个时的花费的步数是一定的,那么,就可以先进行一次预处理,预处理出对于目标棋子在上述条件下每次移动所需的步数。 然后,预处理完成之后,我们会发现每次查询都会变成一个求最短路的问题,用Dijstra或SPFA的话,可以在时限范围内解决。 实现: 定义一个数组Step[x][y][k][h],表示目标棋子在位置(x,y)且空格在目标棋子的k方向上的相邻格子时,目标棋子往h方向移动1格所需的步数,然后用状态[x][y][k]作为节点建图,用各个状态的关系连边,每次询问时重新定义一个源点跟终点,跑最短路就可以得出答案。 (预处理时跑n^2次O(n^2)的BFS就可以了) 复杂度(Dijstra): (n^4+n^2logn) 复杂度(SPFA): (n^4+n^2) 代码(SPFA)(Cpp): #include #include #include #include usingnamespacestd; #defineMAXN32 #defineMAXV50010 #defineinf(1<<26) constintdir[4][2]={{-1,0},{1,0},{0,-1},{0,1}}; structedge{ edge*next; intt,d; edge(){ next=NULL; } }*head[MAXV]; voidAddEdge(ints,intt,intd){ edge*p=new(edge); p->t=t,p->d=d; p->next=head[s]; head[s]=p; } intMap[MAXN][MAXN],n,m,q,ex,ey,sx,sy,tx,ty; intv[MAXN][MAXN][4],V=0; intdist[MAXN][MAXN],Move[MAXN][MAXN][4][4]; intDist[MAXV]; boolf[MAXV]; intS,T; structnode{ intx,y; node(int_x,int_y): x(_x),y(_y){ } }; queue intBfs(intSx,intSy,intTx,intTy){ if(Sx==Tx&&Sy==Ty)return0; while(! Q.empty())Q.pop(); for(inti=0;i++ for(intj=0;j++ dist[i][j]=inf; } } dist[Sx][Sy]=0; Q.push(node(Sx,Sy)); while(! Q.empty()){ nodeu=Q.front(); Q.pop(); for(inti=0;i<4;i++){ if(Map[u.x+dir[i][0]][u.y+dir[i][1]]&&dist[u.x+dir[i][0]][u.y+dir[i][1]]==inf){ dist[u.x+dir[i][0]][u.y+dir[i][1]]=dist[u.x][u.y]+1; if(u.x+dir[i][0]==Tx&&u.y+dir[i][1]==Ty)returndist[u.x][u.y]+1; Q.push(node(u.x+dir[i][0],u.y+dir[i][1])); } } } returninf; } structCmp{ booloperator()(intx,inty){ returnDist[x]>Dist[y]; } }; priority_queue intspfa(){ for(inti=0;i++ memset(f,true,sizeof(f)); while(! Pq.empty())Pq.pop(); Dist[S]=0; Pq.push(S); while(! Pq.empty()){ intu=Pq.top(); Pq.pop(); if(! f[u])continue; f[u]=false; if(u==T)returnDist[T]; for(edge*p=head[u];p;p=p->next){ if(Dist[p->t]>Dist[u]+p->d){ Dist[p->t]=Dist[u]+p->d; f[p->t]=true; Pq.push(p->t); } } } returnDist[T] Dist[T]: -1; } intmain(){ cin>>n>>m>>q; memset(Map,0,sizeof(Map)); for(inti=0;i++ for(intj=0;j++ cin>>Map[i][j]; for(intk=0;k<4;k++){ v[i][j][k]=++V; } } } for(inti=0;i++ for(intj=0;j++ for(intk=0;k<4;k++){ for(inth=0;h<4;h++){ Move[i][j][k][h]=inf; } } } } for(inti=0;i++ for(intj=0;j++ if(Map[i][j]){ Map[i][j]=0; for(intk=0;k<4;k++){ if(Map[i+dir[k][0]][j+dir[k][1]]){ for(inth=0;h<4;h++){ if(Map[i+dir[h][0]][j+dir[h][1]]){ Move[i][j][k][h]=Bfs(i+dir[k][0],j+dir[k][1],i+dir[h][0],j+dir[h][1])+1; } } } } Map[i][j]=1; } } } memset(head,0,sizeof(head)); for(inti=0;i++ for(intj=0;j++ for(intk=0;k<4;k++){ for(inth=0;h<4;h++){ if(Move[i][j][k][h] AddEdge(v[i][j][k],v[i+dir[h][0]][j+dir[h][1]][h^1],Move[i][j][k][h]); } } } } } while(q--){ cin>>ex>>ey>>sx>>sy>>tx>>ty; if(sx==tx&&sy==ty){ cout<<0< continue; } S=++V; T=++V; if(Map[sx][sy]==0||Map[tx][ty]==0){ cout<<-1< continue; } Map[sx][sy]=0; for(inti=0;i<4;i++){ if(Map[sx+dir[i][0]][sy+dir[i][1]]){ intD=Bfs(ex,ey,sx+dir[i][0],sy+dir[i][1]); if(D AddEdge(S,v[sx][sy][i],D); } } } Map[sx][sy]=1; for(inti=0;i<4;i++){ if(Map[tx+dir[i][0]][ty+dir[i][1]]){ AddEdge(v[tx][ty][i],T,0); } } cout< } return0; }
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Noip 提高组 Day2 解题报告 提高 解题 报告