P7406 [JOI 2021 Final] 集合写真
题意
给定一个排列,每次可以交换相邻两个,最少要多少次操作使得
- 对于任意
,都有 。
题解
- 经过观察可以发现,连续下降的数之间只能相差1,也就是说如果有连续下降的一段,它们必定是依次递减1。
- 所以一个合法的序列一定可以这样划分,我们将整个序列划分成若干个不相交的连续下降段,其中每个段的最小值(右端点)一定大于前一个段的最大值(左端点)。 也就是形如(3 2 1)(4) (7 6 5)
- 设
表示值域在1-i之间的数已经排好的最小代价, 。 - 注意到我们在将值域在
的数归位并不会影响值域在 之间的数的相对顺序 - 将值域在
的数归位可以看作这样两个步骤,先将所有值域在 的数移动到 的位置范围,但是两个值域在 不会交换,这一部分的cost就是 - 而第二部分则是交换值域在
的数,cost为 - 具体实现的话可以利用二维前缀和,考虑每一对
会对哪些区间进行贡献,然后进行利用二维差分即可。
#include<bits/stdc++.h>
#define fo(i,a,b) for (ll (i)=(a);(i)<=(b);(i)++)
#define fd(i,b,a) for (ll (i)=(b);(i)>=(a);(i)--)
#define eb emplace_back
#define pi pair<ll,ll>
#define mk(x,y) make_pair((x),(y))
#define lc (o<<1)
#define rc ((o<<1)|1)
//#define A puts("Yes")
//#define B puts("No")
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef double db;
const ll mo1=1e9+7;
const ll mo2=1e9+9;
const ll P=131;
const ll Q=13331;
const ll inf=1ll<<60;
const int N=5e3+5;
ll f[N],a[N],pos[N],n;
struct pre{
ll s[N][N];
pre(){
memset(s,0,sizeof(s));
}
void upd(int a,int b,int c,int d){
s[a][b]++;
s[a][d+1]--;
s[c+1][b]--;
s[c+1][d+1]++;
}
void work(){
fo(i,1,n) fo(j,1,n) s[i][j]+=s[i][j-1];
fo(j,1,n) fo(i,1,n) s[i][j]+=s[i-1][j];
}
};
int main() {
// freopen("data.in", "r", stdin);
// freopen("data.out", "w", stdout);
pre s,t;
scanf("%lld",&n);
fo(i,1,n) {
scanf("%lld",&a[i]);
pos[a[i]]=i;
}
fo(i,1,n) fo(j,i+1,n) if (pos[i]>pos[j]) {
s.upd(1,i,i,j-1);
// printf("%d %d\n",i,j);
}
fo(i,1,n) fo(j,i+1,n) if (pos[i]<pos[j]) t.upd(1,j,i,n);
// return 0;
s.work();
t.work();
fo(i,1,n) f[i]=inf;
fo(i,1,n) fo(j,1,i) {
f[i]=min(f[i],f[j-1]+s.s[j][i]+t.s[j][i]);
}
printf("%lld",f[n]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?