Codeforces Round #719 (Div. 3) E. Arranging The Sheep(字符串+中位数定理)
https://codeforces.com/contest/1520
你在玩“放羊”游戏。这个游戏的目标是让羊排好队。
游戏中的关卡由一个长度为n的字符串描述,由字符“.”组成(空格)和' * '(羊)。
在一次移动中,你可以将任何羊向左移动一格或向右移动一格,如果相应的方格存在并且是空的。
羊一排好,游戏就结束了,也就是说,任何羊之间都不能有空格。
输出
对于每个测试用例输出,您需要完成该级别的最少移动次数。
input
5
6
**.*..
5
*****
3
.*.
3
...
10
*.*...*.**
output
1
0
0
0
9
方法一:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N=200200,M=2002;
LL a[N],b[N];
int main()
{
cin.tie(0); cout.tie(0); ios::sync_with_stdio(false);
int T=1;
cin>>T;
while(T--)
{
LL n;
cin>>n;
string s;
cin>>s;
LL l=0,r=0;
for(int i=0;i<n;i++)
if(s[i]=='*') r++;
LL sum=0;
for(int i=0;i<n;i++)
{
if(s[i]=='*') l++,r--;
else sum+=min(l,r);
}
cout<<sum<<endl;
}
return 0;
}
方法二:
- 先找到每个*的所在位置
- 然后按顺序排序的话,每个*接在前一个的后面需要向前移动多少位置(也就是代码中的偏移量)
- 然后知道了这所有星星黏在一起需要的步数后,用中位数求得最小合并距离
———知识分割线———
中位数定理
给定数轴上的n个点,找出一个到它们的距离之和尽量小的点
结论:这些点的中位数就是目标点。
根据中位数定理,我们可以想到,找到中间的那个星号,然后让其他点都凑到这个点,最终就是答案了。
这样就只用选一个点就够了,刚好是o(n)的。
LL n;
cin>>n;
string s;
cin>>s;
s=" "+s;
LL k=0;
for(int i=1;i<=n;i++)
if(s[i]=='*') b[++k]=i;
for(int i=1;i<=k;i++)
{
b[i]-=i;//减去偏移量
//cout<<b[i]<<" ";
}
LL sum=0;
for(int i=1;i<=k;i++)
sum+=abs(b[i]-b[k/2+1]);
cout<<sum<<endl;