AT_abc393_d [ABC393D] Swap to Gather 题解
题意
给定一串只有 0
和 1
的字符串,可以将相邻的两个字符交换,问至少需要多少步才能让所有的 1
相邻。
思路
非常结论的一道题目。
设有 mmm 个 1
,则把所有的 1
都移到与第 m2+1\frac{m}{2}+12m+1 个 1
相邻的位置有最优解。
为什么,举例说明一下:
若 mmm 为奇数。
假设有这么一串数:
10⋯0⏟a个010⋯0⏟b个011\underbrace{0\cdots 0}_{a个0}1\underbrace{0\cdots 0}_{b个0}11a个00⋯01b个00⋯01
若把所有的 1
都移到与中间那个 1
相邻的位置,则所需步数为:a+ba+ba+b。
若要把所有的 1
都移到与两旁的 1
相邻的位置,则所需步数为:a+2×ba+2\times ba+2×b 或 2×a+b2\times a+b2×a+b。
很显然,这两个答案一定都会比 a+ba+ba+b 大。所以,在 mmm 为奇数时,把所有的 1
都移到与第 m2+1\frac{m}{2}+12m+1 个 1
相邻的位置时有最优解。
若 mmm 为偶数。
假设有这么一串数:
10⋯0⏟a个010⋯0⏟b个010⋯0⏟c个011\underbrace{0\cdots 0}_{a个0}1\underbrace{0\cdots 0}_{b个0}1\underbrace{0\cdots 0}_{c个0}11a个00⋯01b个00⋯01c个00⋯01
若要移到与第一个 1
相邻的位置,则所需步数为:a×3+b×2+ca\times 3+b\times 2+ca×3+b×2+c。
若要移到与第二个 1
相邻的位置,则所需步数为:a+b×2+ca+b\times 2+ca+b×2+c。同理,移到与第三个 1
相邻的位置所需步数也是:a+b×2+ca+b\times 2+ca+b×2+c。
若要移到与第四个 1
相邻的位置,则所需步数为:a+b×2+c×3a+b\times 2+c\times 3a+b×2+c×3。
此时,可以发现把所有的 1
都移到与第 m2\frac{m}{2}2m 个 1
到第 m2+1\frac{m}{2}+12m+1 个 1
相邻的位置时都有最优解。所以不妨也把所有的 1
都移到与第 m2+1\frac{m}{2}+12m+1 个 1
相邻的位置。
其实这题就是一个绝对值方程求最值。
代码
直接模拟即可。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN = 5e5 + 10;
int n;
char a[MAXN];
int num;
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
for(register int i = 1;i <= n;i ++) {
cin >> a[i];
if(a[i] == '1')
num ++;
}
int k , cnt = 0 , ans = 0;
for(register int j = 0 , i = 1;j < num / 2 + 1;i ++)
if(a[i] == '1') {
k = i;
j ++;
}
for(register int i = k - 1;i >= 1;i --)
if(a[i] == '1') {
ans += (k - i - 1 - cnt);
cnt ++;
}
cnt = 0;
for(register int i = k + 1;i <= n;i ++)
if(a[i] == '1') {
ans += (i - k - 1 - cnt);
cnt ++;
}
cout << ans;
}