题解 CF612F 【Simba on the Circle】

xtx1092515503

2020-12-21 19:27:40

Solution

挺烦人的一道DP题。 ------------ 首先,本题的阶段是很容易设想出来的:因为要求“输出的东西不降”,所以必须先将所有 $1$ 输出,然后是所有 $2$,然后是所有 $3$……在不同的数字间,转移是有序的;但是在同一数字间,转移就可能不太trival了。 首先先设出DP状态。设 $f_i$ 表示若 $i$ 是所有值为 $a_i$ 的位置中第一个被输出的,此时所移动的最短距离,再设 $g_i$ 表示若 $i$ 是所有值为 $a_i$ 的位置中最后一个被输出的,此时所移动的最短距离。则答案即为 $$\min\limits_{a_i\text{ is maximum}}g_i$$ 先考虑不同数字间的转移。假如 $j,k$ 分别是一个小一点的数和一个大一点的数,则有 $$g_j+\min\Big\{(k-j)\bmod n,(j-k)\bmod n\Big\}\rightarrow f_k$$ 因为 $n$ 只有 $2000$,所以暴力枚举这样的 $(j,k)$ 进行转移即可。 然后再考虑相同数字间的转移。我们可以大胆猜测,假如我们从一个 $f_j$ 转移到 $g_k$,则必定是先顺时针/逆时针走到 $k$ 的前一个数,然后再掉头一路走到 $k$。 具体式子很长,直接看代码即可。明显这里仍然可以 $n^2$ 枚举转移。 比较恶心的是输出,不同数字间的转移还好,烦人的是相同数字间的转移。按照上文所述的实际意义进行转移即可,详情见代码。 总时间复杂度 $O(n^2)$。 代码: ```cpp #include<bits/stdc++.h> using namespace std; int n,m,p,a[2010],f[2010],g[2010],F[2010],G[2010],res=0x3f3f3f3f;//f:the minimal starting from i; g:the minimal ending at i vector<int>v[2010],u; stack<int>s; int main(){ scanf("%d%d",&n,&p),p--,memset(f,0x3f,sizeof(f)),memset(g,0x3f,sizeof(g)); for(int i=0;i<n;i++)scanf("%d",&a[i]),u.push_back(a[i]); sort(u.begin(),u.end()),u.resize(m=unique(u.begin(),u.end())-u.begin()); for(int i=0;i<n;i++)v[a[i]=lower_bound(u.begin(),u.end(),a[i])-u.begin()+1].push_back(i); // for(int i=0;i<n;i++)printf("%d ",a[i]);puts(""); // for(int i=1;i<=m;i++){for(auto j:v[i])printf("%d ",j);puts("");} for(auto i:v[1])f[i]=min((i+n-p)%n,(p+n-i)%n),F[i]=-1; for(int i=1;i<=m;i++){ int len=v[i].size(); for(int j=0;j<len;j++)for(int k=0;k<len;k++){ if(j==k)continue; int J=v[i][j],K=v[i][k]; int A=(v[i][(k+len-1)%len]+n-J)%n*2+(J+n-K)%n; int B=(J+n-v[i][(k+1)%len])%n*2+(K+n-J)%n; if(g[K]>f[J]+min(A,B))g[K]=f[J]+min(A,B),G[K]=J; } if(len==1)g[v[i][0]]=f[v[i][0]],G[v[i][0]]=v[i][0]; if(i==m)continue; for(auto j:v[i])for(auto k:v[i+1])if(f[k]>g[j]+min((k+n-j)%n,(j+n-k)%n))f[k]=g[j]+min((k+n-j)%n,(j+n-k)%n),F[k]=j; } // for(int i=0;i<n;i++)printf("%d ",f[i]);puts(""); // for(int i=0;i<n;i++)printf("%d ",g[i]);puts(""); for(auto i:v[m])res=min(res,g[i]); printf("%d\n",res); for(auto K:v[m]){ if(g[K]!=res)continue; for(int i=m;i;i--){ int len=v[i].size(); int J=G[K]; int j=lower_bound(v[i].begin(),v[i].end(),J)-v[i].begin(),k=lower_bound(v[i].begin(),v[i].end(),K)-v[i].begin(); int A=(v[i][(k+len-1)%len]+n-J)%n*2+(J+n-K)%n; int B=(J+n-v[i][(k+1)%len])%n*2+(K+n-J)%n; if(len>1){ if(A<B){ for(int l=k;(l+1)%len!=j;(++l)%=len)s.push(-(v[i][(l+1)%len]+n-v[i][l])%n); s.push(-(v[i][(k+len-1)%len]+n-v[i][(j+len-1)%len])%n); for(int l=(k+len-1)%len;l!=j;(l+=len-1)%=len)s.push((v[i][l]+n-v[i][(l+len-1)%len])%n); }else{ for(int l=k;(l+len-1)%len!=j;(l+=len-1)%=len)s.push((v[i][l]+n-v[i][(l+len-1)%len])%n); s.push((v[i][(j+1)%len]+n-v[i][(k+1)%len])%n); for(int l=(k+1)%len;l!=j;(++l)%=len)s.push(-(v[i][(l+1)%len]+n-v[i][l])%n); } } A=J,B=F[J]; if(B==-1)B=p; s.push((A+n-B)%n<(B+n-A)%n?(A+n-B)%n:-(B+n-A)%n); K=B; } break; } // auto S=s;while(!S.empty())printf("%d ",(p+=S.top()+n)%n),S.pop();puts(""); while(!s.empty())printf("%c%d\n",(s.top()>=0?'+':'-'),abs(s.top())),s.pop(); return 0; } ```