Noip提高组Day2解题报告.docx

上传人:b****3 文档编号:26891359 上传时间:2023-06-23 格式:DOCX 页数:12 大小:43.50KB
下载 相关 举报
Noip提高组Day2解题报告.docx_第1页
第1页 / 共12页
Noip提高组Day2解题报告.docx_第2页
第2页 / 共12页
Noip提高组Day2解题报告.docx_第3页
第3页 / 共12页
Noip提高组Day2解题报告.docx_第4页
第4页 / 共12页
Noip提高组Day2解题报告.docx_第5页
第5页 / 共12页
点击查看更多>>
下载资源
资源描述

Noip提高组Day2解题报告.docx

《Noip提高组Day2解题报告.docx》由会员分享,可在线阅读,更多相关《Noip提高组Day2解题报告.docx(12页珍藏版)》请在冰豆网上搜索。

Noip提高组Day2解题报告.docx

Noip提高组Day2解题报告

第二题:

花匠(动态规划)

1.令S[i][1]表示以i为结尾,且降序到达a[i]的最长抖动序列长度;令S[i][0]表示以i为结尾,且升序到达a[i]的最长抖动序列长度。

依然设数组S[i][0/1],但考虑如下递推公式:

   

(1)a[i+1]>a[i]:

S[i+1][0]=max(S[i][1]+1,S[i][0]);

S[i+1][1]=S[i][1];

   

(2)a[i+1]

S[i+1][0]=S[i][0];

S[i+1][1]=max(S[i][0]+1,S[i][1]);

   (3)a[i+1]==a[i]:

S[i+1][0]=S[i][0];

S[i+1][1]=S[i][1];

  S[1][0]=S[1][1]=1.

算法优化后,再一次编写程序,O(n)的时间复杂度,当然是顺利AC了,代码如下:

2.这道题明显可以用类似最长上升子序列的动态规划求解,易得思路如下:

用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;

}

其实再进一步分析,发现问题可以简化成为求转折点数的问题,又是一个O(n),对序列缩点,连续递减的点和连续递增的点是可以缩到一个代表性的点上的,比如说样例给的53212,可以缩成5,1,2或3,1,2或2,1,2,即532这三个连续递减的点实际上可以由一个点代替,1是一个转折点,于是你也可以说是找转折点个数。

 

第三题:

华容道 (最短路)

这道题的数据范围是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){

}

};

queueQ;

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,Cmp>Pq;

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;

}

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高中教育 > 初中教育

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1