专栏文章

ABC393D题解

AT_abc393_d题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miq8sygf
此快照首次捕获于
2025/12/04 00:50
3 个月前
此快照最后确认于
2025/12/04 00:50
3 个月前
查看原文

题意

给定一个长度为 nn 的 01 串,每次可以交换两个相邻的位置,问至少多少次交换可以让所有的 11 都在一起。

思路

容易发现最中间的 11 不动,把两边的向中间靠是最优的。
如何确定最中间的?考虑 11 的个数 cntcnt,如果是奇数,那肯定就是第 cnt+12\frac{cnt+1}{2}11
对于每个为 11 的位置计算移动的步数。设第 ii11 的位置为 aia_imid=cnt+12mid=\frac{cnt+1}{2},第 ii 个为 11 的位置需要移动的步数是 (amidai1)(midi1)(|a_{mid}-a_i|-1)-(|mid-i|-1)
这是因为如果从 ii 位置移动到与 midmid 位置相邻,需要 amidai1|a_{mid}-a_i|-1 步,但由于中间隔了 midi1|mid-i|-111,所以这些步不用动。
如果 cntcnt 是偶数,中间的可能是 cnt2\frac{cnt}{2}cnt2+1\frac{cnt}{2}+1。那就令 mid=cnt2mid=\frac{cnt}{2}mid=cnt2+1mid=\frac{cnt}{2}+1 各跑一遍,两次答案取 min\min 即可。

AC Code

CPP
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5+5;
int n,cnt=0,cur=0,a[N],ans=0;
char s[N];
signed main(){
	cin>>n;
	cin>>s+1;
	for(int i=1;i<=n;i++)  if(s[i]=='1') a[++cnt]=i;
	if(cnt&1){
		int mid=(cnt+1)/2,val=a[(cnt+1)/2];
		for(int i=1;i<=cnt;i++) ans+=max(0ll,abs(val-a[i])-abs(mid-i));
		cout<<ans;
	}else{
		int mid1=cnt/2,mid2=cnt/2+1;
		int t1=0,t2=0;
		for(int i=1;i<=cnt;i++) t1+=max(0ll,abs(a[mid1]-a[i])-abs(mid1-i));
		for(int i=1;i<=cnt;i++) t2+=max(0ll,abs(a[mid2]-a[i])-abs(mid2-i));
		cout<<min(t1,t2);
	}
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...