当前位置: 代码迷 >> 综合 >> 【DP】CodeForces612F Simba on the Circle
  详细解决方案

【DP】CodeForces612F Simba on the Circle

热度:116   发布时间:2023-09-27 07:12:02.0

题意:

给出一个环状的序列,每个位置有一个值aiai,初始位置为s,现在要求从小到大依次遍历每个点。要求总步数尽可能小。
序列长度N2000N≤2000


分析:

这是一道代码题。。。。
所谓代码题,就是思路异常简单,但实现起来细节暴多的题。。。。

第一问:

其实大致方法很简单,定义dp[i]dp[i]表示将所有ajaiaj≤ai的位置都遍历后,停在aiai位置的最小步数(注:必须满足在遍历aj=aiaj=ai这一层时,ii位置只能经过一次)。

转移就非常暴力了。
我们对 a i 相同的在同一次处理,定义为SS
定理序列 G 表示aSiaSi为严格小于aiai的最大的数组成的序列(说白了就是上一次处理的那些位置)

所以dpi=min{ dpGj+GjSii}dpi=min{dpGj+从Gj出发遍历所有Si中的点最终到达i的最小步数}
我们可以O(n)地枚举GjGj,然后用O(1)的复杂度求出后面那一坨。。。(总复杂度O(n2)O(n2)

所以,恶心的就是如何用O(1)的复杂度求出后面那一坨。。。。

首先要引入2个辅助函数
len(u,v)len(u,v)表示从u到v的最小步数。
len(u,v,k)len(u,v,k)表示从u出发,不经过k到达v的步数。
prepprep表示在S中i左边的第一个位置(prep=(i?1+|s|)mod|s|)(prep=(i?1+|s|)mod|s|)
lasplasp表示在S中i右边的第一个位置(lasp=(i+1)mod|s|)(lasp=(i+1)mod|s|)
由于我们定义的dpidpi的特殊要求(在当前层中,ii位置只经过一次)

所以我们可以分为这么3种情况:

1、

【DP】CodeForces612F Simba on the Circle

这种情况(好吧其实是2种)满足 p r e p = l a s p
代价可以表示为:len(Gj,Sprep)+len(Sprep,Si)len(Gj,Sprep)+len(Sprep,Si)

2、

【DP】CodeForces612F Simba on the Circle
这种情况满足(l?>Sprep,r?>Slasp,x?>Gj)(l?>Sprep,r?>Slasp,x?>Gj)
【DP】CodeForces612F Simba on the Circle
说白了,就是GjGj被包在Sprep,SiSprep,SiSi,SlaspSi,Slasp之间。

这种情况下我们肯定要从GjGj出发,绕外面所有SS中的点一圈,再从另一侧回来

这部分可以等价地表示为: n ? l e n ( G j , S i , S p r e p ) ( = n ? l e n ( G j , S i , S l a s p ) )

3、

【DP】CodeForces612F Simba on the Circle

这部分就相对常规一些,公式也相对复杂一些:
【DP】CodeForces612F Simba on the Circle
我们可以走基佬紫和原谅绿两种颜色表示的路径。

取个min就可以了

所以表示为:

len(Gj,Sprep,Si)+len(Gj,Slasp,Si)+ min{ len(Gj,Sprep,Si)+len(Slasp,Si),len(Gj,Slasp,Si)+len(Sprep,Si)}len(Gj,Sprep,Si)+len(Gj,Slasp,Si)+min{len(Gj,Sprep,Si)+len(Slasp,Si),len(Gj,Slasp,Si)+len(Sprep,Si)}

min里面前者表示基佬紫走法
后者表示原谅绿走法

然后。。。我们就可以得到第一问的答案了。。

第二问

和所有DP求方案的题一样,这道题也需要记录转移路径。

这里还要借助一个辅助函数len1(u,v)len1(u,v)表示从u走到v的小步数(含正负)
然后还是分为上面3类讨论:

对于第1类:

走法无非是【DP】CodeForces612F Simba on the Circle

应该很简单我就直接粘代码了。

对于第2类:

上面已经把走法解释过了,所以我还是直接上代码吧:
【DP】CodeForces612F Simba on the Circle

对于第3类:

这里的具体走法稍微有点巧妙。

首先还是判断一下哪条路代价最小,然后走小的那一边。

这里我们可以直接从GjGj走到SprepSprep,再以递减的顺序走完SS中的点回到 S i

或从GjGj走到SlaspSlasp,以递增的顺序走完SS中的点回到 S i

实在还有不懂的就去看代码吧。。。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 2010
#define INF 0x3f3f3f3f
using namespace std;
int n,s;
int dp[MAXN],com[MAXN],cnt;
vector<int> las[MAXN],now;
pair<int,int> a[MAXN];
int len(int x,int y){if(x>y)swap(x,y);return min(y-x,x+n-y);
}
int len(int x,int y,int blo){if(x>y)swap(x,y);if(blo==x||blo==y)return len(x,y);if(x<blo&&blo<y)return x+n-y;if(blo<x||blo>y)return y-x;
}
bool checkin(int x,int l,int r){if(l<r)return x>=l&&x<=r;elsereturn x<=r||x>=l;
}
void solve(){int m=now.size();for(int i=0;i<m;i++)for(int j=0;j<las[cnt].size();j++){int prep=now[(i-1+m)%m];int lasp=now[(i+1+m)%m];int u=now[i];int v=las[cnt][j];int val=0;if(prep==lasp){val=len(v,prep)+len(prep,u);//PF("[1]");}else if(checkin(v,prep,lasp)){val=n-len(u,v,prep);//PF("[2]");}elseval=len(v,prep,u)+len(v,lasp,u)+min(len(v,lasp,u)+len(prep,u),len(v,prep,u)+len(lasp,u));//PF("{
    %d %d}\n",u,val);if(cnt!=0)val+=dp[las[cnt][j]];if(val<dp[now[i]]){dp[now[i]]=val;com[now[i]]=j;  }}cnt++;for(int i=0;i<m;i++)las[cnt].push_back(now[i]);now.clear();
}
vector<int> print;
int len1(int x,int y){//PF("{
    %d %d}\n",x,y);int lenx=len(x,y);if((x+lenx-1)%n+1==y)return lenx;elsereturn -lenx;
}
void get_ans(int x,int tim){if(tim!=1)get_ans(com[las[tim][x]],tim-1);int m=las[tim].size();int prep=las[tim][(x-1+m)%m];int lasp=las[tim][(x+1)%m];int u=las[tim][x];int v=las[tim-1][com[u]];int val=0;if(prep==lasp){print.push_back(len1(v,prep));if(prep!=u)print.push_back(len1(prep,u));}else if(checkin(v,prep,lasp)){if(checkin(v,prep,u)){print.push_back(len1(v,prep));for(int j=(x-1+m)%m;j!=x;j=(j-1+m)%m)print.push_back(len1(las[tim][j],las[tim][(j-1+m)%m]));}else{print.push_back(len1(v,lasp));for(int j=(x+1)%m;j!=x;j=(j+1)%m)print.push_back(len1(las[tim][j],las[tim][(j+1)%m]));}}else{if(len(v,lasp,u)+len(prep,u)<len(v,prep,u)+len(lasp,u)){print.push_back(len1(v,lasp));for(int j=(x+1)%m;j!=x;j=(j+1)%m)print.push_back(len1(las[tim][j],las[tim][(j+1)%m]));}else{print.push_back(len1(v,prep));for(int j=(x-1+m)%m;j!=x;j=(j-1+m)%m)print.push_back(len1(las[tim][j],las[tim][(j-1+m)%m]));}}//PF("{
    %d %d %d}\n",u,tim,print.size());
}
int main(){memset(dp,INF,sizeof dp);SF("%d%d",&n,&s);for(int i=1;i<=n;i++){SF("%d",&a[i].first);a[i].second=i;}sort(a+1,a+1+n);las[0].push_back(s);now.push_back(a[1].second);for(int i=2;i<=n;i++){if(a[i].first!=a[i-1].first){solve();}now.push_back(a[i].second);}solve();/*for(int i=0;i<=cnt;i++){for(int j=0;j<las[i].size();j++)PF("{%d %d} ",las[i][j],dp[las[i][j]]);PF("\n");}*/int minid=0,minv=INF;for(int i=0;i<las[cnt].size();i++)if(dp[las[cnt][i]]<minv){minid=i;minv=dp[las[cnt][minid]];   }PF("%d\n",minv);get_ans(minid,cnt);for(int i=0;i<print.size();i++){if(print[i]>=0)PF("+%d\n",print[i]);elsePF("%d\n",print[i]);}
}
  相关解决方案