Loading

Codeforces Round #719 (Div. 3) E. Arranging The Sheep(中位数)

You are playing the game "Arranging The Sheep". The goal of this game is to make the sheep line up. The level in the game is described by a string of length 𝑛n, consisting of the characters '.' (empty space) and '*' (sheep). In one move, you can move any sheep one square to the left or one square to the right, if the corresponding square exists and is empty. The game ends as soon as the sheep are lined up, that is, there should be no empty cells between any sheep.

For example, if 𝑛=6n=6 and the level is described by the string "**.*..", then the following game scenario is possible:

  • the sheep at the 44 position moves to the right, the state of the level: "**..*.";
  • the sheep at the 22 position moves to the right, the state of the level: "..*.";
  • the sheep at the 11 position moves to the right, the state of the level: ".**.*.";
  • the sheep at the 33 position moves to the right, the state of the level: ".*.**.";
  • the sheep at the 22 position moves to the right, the state of the level: "..***.";
  • the sheep are lined up and the game ends.

For a given level, determine the minimum number of moves you need to make to complete the level.

Input

The first line contains one integer 𝑡t (1≤𝑡≤1041≤t≤104). Then 𝑡t test cases follow.

The first line of each test case contains one integer 𝑛n (1≤𝑛≤1061≤n≤106).

The second line of each test case contains a string of length 𝑛n, consisting of the characters '.' (empty space) and '*' (sheep) — the description of the level.

It is guaranteed that the sum of 𝑛n over all test cases does not exceed 106106.

Output

For each test case output the minimum number of moves you need to make to complete the level.

Example

input

Copy

5
6
**.*..
5
*****
3
.*.
3
...
10
*.*...*.**

output

Copy

1
0
0
0
9

题意就是给定一个包含*和.的串,每次可以将一个*移动到相邻的.,问最少移动多少次可以使得所有*相邻。

利用中位数思想,首先可以知道最优方案一定是某个*不动而移动其他的某些*。这样我们可以枚举不动的*的位置,然后把其他的*靠过来,常数时间计算贡献。最后对答案取min即可。

至于如何计算贡献:首先我们获取所有的*的位置存入一个数组,然后枚举数组中的元素。枚举到某个元素我们可以知道它左边的位置的个数以及左边的位置的和(可以处理出前缀和也可以直接计算)。

tmp1 = 1ll * (i - 1) * a[i] - sum1[i - 1] - 1ll * (1 + i - 1) * (i - 1) / 2;

即计算所有在不变的位置的左边的*到不变的位置的距离再减去归位时候左边的*到不变的位置的距离。处理右边同理。

#include <bits/stdc++.h>
using namespace std;
int a[1000005], n, m;
long long sum1[1000005], sum2[1000005];
int main() {
	int t;
	cin >> t;
	sum1[0] = 0;
	while(t--) {
		string s;
		cin >> n;
		cin >> s;
		m = 0;
		long long ans = 1e16;
		for(int i = 0; i < s.size(); i++) {
			if(s[i] == '*') {
				++m;
				a[m] = i;
			}
		}
		sum1[0] = 0;
		for(int i = 1; i <= m; i++) {
			sum1[i] = sum1[i - 1] + a[i];
		}
		sum2[m + 1] = 0;
		for(int i = m; i >= 1; i--) {
			sum2[i] = sum2[i + 1] + a[i];
		}
		for(int i = 1; i <= m; i++) {
			long long tmp1 = 0, tmp2 = 0;
			tmp1 = 1ll * (i - 1) * a[i] - sum1[i - 1] - 1ll * (1 + i - 1) * (i - 1) / 2;// - (1 + i - 1) * 1ll * (i - 1) / 2;
			tmp2 = sum2[i + 1] - 1ll * (m - i) * a[i] - 1ll * (1 + (m - i)) * (m - i) / 2;
			ans = min(ans, tmp1 + tmp2);

		}
		if(ans != 1e16) cout << ans << endl;
		else cout << 0 << endl;
	}
	return 0;
}
posted @ 2021-05-06 19:02  脂环  阅读(243)  评论(0编辑  收藏  举报