题目描述
小爱正在体验一款推箱子游戏。游戏每一关由长度为
n
n
n 的字符“_”(空格)和"@"(箱子)组成初始状态,让当前所有箱子集中到一块即可过关。
在一个动作中,如果目标移动的位置存在并且是空的,你可以将任何箱子向左移动一个位置或向右移动一个位置。当前所有箱子一排好,即任意两个箱子之间都不存在空格,方可进入下一关。 此款游戏共有
t
t
t 关,确定通过每一关卡所需的最小移动次数。
输入
第一行:一个整数
t
t
t ,表示
t
t
t 个关卡。
接下来是
2
t
2 t
2t 行表示每一关初始情况。
一个整数
n
n
n ,表示当前可用位置情况
一个长度为
n
n
n 的字符串,只包含“_”(空格)和"@"(箱子).
输出
输出共 t t t 行,每一行表示通过每一关卡所需的最小移动次数。
数据范围
。对于
30
%
3 0 \%
30% 的数据,
1
≤
t
≤
10
,
1
≤
∑
n
i
≤
1
0
3
1 \leq t \leq1 0, 1 \leq\sum n_{i} \leq1 0^{3}
1≤t≤10,1≤∑ni≤103 .
。对于
60
%
6 0 \%
60% 的数据,
1
≤
t
≤
1
0
3
,
1
≤
∑
n
i
≤
5
∗
1
0
5
1 \leq t \leq1 0^{3}, 1 \leq\sum n_{i} \leq5 * 1 0^{5}
1≤t≤103,1≤∑ni≤5∗105 。
。对于
100
%
1 0 0 \%
100% 的数据,
1
≤
t
≤
1
0
4
,
1
≤
∑
n
i
≤
1
0
6
1 \leq t \leq1 0^{4}, 1 \leq\sum n_{i} \leq1 0^{6}
1≤t≤104,1≤∑ni≤106 .
样例
输入:
3
6
@@@__
3
@
10
@@__@@@
输出:
1
0
9
说明:
@@@___ (最右边箱子向左移动1个单位)
@ (移动0次)
3 + 4 + 1 + 1 = 9 。左边第2个箱子向右移动3个单位、最左边箱子向右移动4个单位、 右边第2个箱子向左移动1个单位、最右边箱子向左移动1个单位
题目分析
我们可以贪心地分析一下,最终一定是将其他的’@‘向某一个’@‘集中,这样是最优。
因此我们可以枚举每一个’@‘,假设其余所有的’@‘都要向该’@‘移动。
首先,我们将两个’@‘之间的间距存下来
vector<int> dd;
for(int i = 0;i < n;i++)
if(s[i] == '@'){
int last = i;
for(int j = i + 1;j < n;j++){
if(s[j] == '@'){
dd.push_back(j - last - 1);
last = j;
}
}
break;
}
举个例子:
(1)当所有的’@‘都向第1个’@‘集中时,
每一段的贡献分别为 5,4,3,2,1
(2)当所有的’@‘都向第2个’@‘集中时,
每一段的贡献分别为 1,4,3,2,1
(3)当所有的’@‘都向第3个’@‘集中时,
每一段的贡献分别为1,2,3,2,1
因此,我们可以发现,
当所有的’@‘都向第1个’@‘集中时,每一段的贡献分别为5,4,3,2,1
当所有的’@‘都向第i(i >= 2)个’@‘集中时,前i - 1段的贡献变成 1,2,3,…,i - 1
所以如果我们从2到n枚举i时,这相当于一个递推的过程。
具体到这个题,假设有dd.size()段间隔,下标从0开始,则第i个间隔的贡献变化之前为dd.size() - 1,变化之后为 i + 1
LL tmp = res;
for(int i = 0;i < dd.size();i++){
tmp = tmp - (dd.size() - i) * dd[i] + (i + 1) * dd[i];
res = min(res,tmp);
}
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int n;
string s;
void solve(){
cin >> n >> s;
vector<int> dd;
for(int i = 0;i < n;i++)
if(s[i] == '@'){
int last = i;
for(int j = i + 1;j < n;j++){
if(s[j] == '@'){
dd.push_back(j - last - 1);
last = j;
}
}
break;
}
LL res = 0;
for(int i = 0;i < dd.size();i++) res += (dd.size() - i) * dd[i];
LL tmp = res;
for(int i = 0;i < dd.size();i++){
tmp = tmp - (dd.size() - i) * dd[i] + (i + 1) * dd[i];
res = min(res,tmp);
}
cout << res << '\n';
}
int main(){
ios::sync_with_stdio(false);;
cin.tie(0),cout.tie(0);
int t;
cin >> t;
while(t--){
solve();
}
return 0;
}