【学习笔记】[BalticOI 2007 Day 1] Ranklist Sorting

论文题(挺考验语文阅读能力的,足足花了我一晚上+一下午)

论文出处

首先感性地得到两个推论(这是我们后续按顺序 dp 的基础):

  1. 最有决策中一定是从大往小操作
  2. 对于数 x 来说,要么在原地不动,要么移动到 x+1 的前一个位置

现在我们修改一下这个操作的定义:

在这里插入图片描述
我们不改变没有操作的点的位置,而是 并列放置 。这样的放置对后面 dp 转移方程的推导很有帮助。

我们可以令 f [ x ] [ p 2 ] f[x][p2] f[x][p2] 表示把 x x x 移动到原序列的 p 2 p2 p2 位置且 x + 1 x+1 x+1 n n n 都在 p 2 p2 p2 的最小费用。 p o s [ x ] pos[x] pos[x] 表示 x x x 在原序列中位置。

先来考虑 p o s [ x ] < p 2 pos[x]<p2 pos[x]<p2 即往后移动的情况。

我们定义 c ( p , x ) c(p,x) c(p,x) 表示 1 到 p 中小于 x 的位置的个数 + 1。那么 x 的真实位置其实就是 c ( p , x ) c(p,x) c(p,x)

有方程 f[x][p2]=f[x+1][p2]+c(p,x)+c(p2,x) (之所以 -1 是因为要移动到 x+1 的前一位)

那么 p o s [ x ] > p 2 pos[x]>p2 pos[x]>p2 呢?

在这里插入图片描述
显然可以归到上一种情况,即 f[x][p2]=f[x+1][p2]+c(p,x)+c(p2,x)+(4-3) (注意这里 (4-3) 其实是提前计算的,后面会讲)

下面我们考虑如何计算对未来状态的影响。

还是考虑 图2.7 。这个时候 5 都对未来决策造成了影响(3 的位置变成了 c(5,3)+2),(注意这里其实是 5 对 3 的位置造成了影响,和 4 没有任何关系),换句话说对象应该是 所有 p < x < p 2 p<x<p2 p<x<p2 s [ x ] < i s[x]<i s[x]<i 的点,而且对每个 s[x] 的影响恰好为 i − s [ x ] i-s[x] is[x]

综上所述,dp 转移方程为:

  1. f [ i ] [ j ] = f [ i + 1 ] [ j ] + c ( p o s [ i ] , i ) + c ( j , i ) f[i][j]=f[i+1][j]+c(pos[i],i)+c(j,i) f[i][j]=f[i+1][j]+c(pos[i],i)+c(j,i)
  2. f [ i ] [ p o s [ i ] ] = min ⁡ ( f [ i + 1 ] [ j ] + ∑ p o s [ i ] < x < j [ s [ x ] < i ] ( i − s [ x ] ) ∣ j > p o s [ i ] ) f[i][pos[i]]=\min(f[i+1][j]+\sum_{pos[i]<x<j}[s[x]< i](i-s[x])|j>pos[i]) f[i][pos[i]]=min(f[i+1][j]+pos[i]<x<j[s[x]<i](is[x])j>pos[i])

时间复杂度 O ( n 2 ) O(n^2) O(n2) (优秀!)

最后我们写一个 dfs 输出方案即可。

Luogu 唯二 AC 解 (233)

#include<bits/stdc++.h> #define db double #define ll long long #define mkp make_pair #define pii pair<int,int> #define inf 0x3f3f3f3f #define fi first #define se second using namespace std; const int Maxn=1005; pii a[Maxn]; int n,tot,pos[Maxn],s[Maxn],dp[Maxn][Maxn],pre[Maxn],l[Maxn][Maxn],r[Maxn][Maxn],add[Maxn]; pii b[Maxn]; bool cmp(pii x,pii y) { return x.fi>y.fi||x.fi==y.fi&&x.se<y.se; } void dfs(int i,int j) { if(i==n) return; if(pos[i]!=j) { dfs(i+1,j); //输出把当前点的实际位置移动到 j 的实际位置 tot++; b[tot].fi++; b[tot].fi+=add[i]; b[tot].se++; //交换到的位置不变 ? for(int k=1;k<=j;k++) { if(s[k]<i) b[tot].se++; } for(int k=1;k<pos[i];k++) { if(s[k]<i) b[tot].fi++; } } else { //对后面的决策造成影响 for(int k=pos[i]+1;k<pre[i];k++) { if(s[k]<i) { add[s[k]]+=i-s[k]; } } dfs(i+1,pre[i]); } } int main() { memset(dp,0x3f,sizeof dp); cin>>n; for(int i=1;i<=n;i++) { cin>>a[i].fi; a[i].se=i; } sort(a+1,a+1+n,cmp); for(int i=1;i<=n;i++) { pos[i]=a[i].se; s[a[i].se]=i; } n++,dp[n][n]=0,s[n]=n; // for(int i=1;i<=n;i++) { // printf("%d\n",s[i]); // } for(int i=n;i>=1;i--) { int v1=1,v2=1; for(int j=1;j<pos[i];j++) { if(s[j]<i) { v1++; } } for(int j=1;j<=n;j++) { if(s[j]<i) { v2++; } if(dp[i+1][j]+v1+v2<dp[i][j]) { dp[i][j]=dp[i+1][j]+v1+v2; l[i][j]=v1; r[i][j]=v2; } } int tmp=0; for(int j=pos[i]+1;j<=n;j++) { if(dp[i+1][j]+tmp<dp[i][pos[i]]) { dp[i][pos[i]]=dp[i+1][j]+tmp; pre[i]=j; } if(s[j]<i) { tmp+=i-s[j]; } } } int ans=inf,xo=0; for(int i=1;i<=n;i++) { if(dp[1][i]<ans) { ans=dp[1][i]; xo=i; } } dfs(1,xo); printf("%d\n",tot); for(int i=1;i<=tot;i++) { printf("%d %d\n",b[i].fi,b[i].se); } }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530226.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(14)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示