题目如下:

思路 or 题解
我们发现不在序列首尾的 111 对整体得分的贡献一定是 111111 (作为个位和十位各出现一次),而 111 开头的对得分的贡献为 101010 ,末尾111的对得分的贡献为 111 ,所以我们希望能有中间的111移到开头或者末尾去,如果中间没有111 也可以把开头的 111 移动到末尾去,模拟这个过程即可,一个位置的 111 移动到另一个位置需要消耗的交换次数是这两个位置之间的距离.
AC代码如下:
const int N = 100009;
int n, k;
char s[N];
int cal()
{
int res = 0;
for (int i = 2; i <= n; i++)
res += (s[i - 1] - '0') * 10 + s[i] - '0';
return res;
}
void solve()
{
cin >> n >> k;
cin >> s + 1;
if (s[1] == '1' && s[n] == '1')
{
cout << cal() << '\n';
return;
}
else if (s[1] == '1' && s[n] == '0')
{
for (int i = 2; i < n; i++)
{
if (s[i] == '1' && (n - i) <= k)
{
swap(s[i], s[n]);
cout << cal() << '\n';
return;
}
}
if (n - 1 <= k)
{
swap(s[1], s[n]);
cout << cal() << '\n';
return;
}
}
else if (s[1] == '0' && s[n] == '1')
{
for (int i = 2; i < n; i++)
{
if (s[i] == '1' && (i - 1) <= k)
{
swap(s[i], s[1]);
cout << cal() << '\n';
return;
}
}
}
else
{
int idx = n - 1;
for (int i = n - 1; i > 1; i--)
{
if (s[i] == '1' && (n - i) <= k)
{
swap(s[i], s[n]);
idx = i - 1;
k -= (n - i);
break;
}
}
for (int i = 2; i <= idx; i++)
{
if (s[i] == '1' && (i - 1) <= k)
{
swap(s[i], s[1]);
break;
}
}
}
cout << cal() << '\n';
}
int main()
{
buff;
int _;
cin >> _;
while (_--)
solve();
}
该博客主要讨论了一种针对含有111子串的字符串序列,通过交换字符来最大化得分的算法。当111不在序列首尾时,通过模拟移动111至首尾的过程,计算所需的最小交换次数。代码中定义了计算当前得分的函数,并根据不同的字符串开头和结尾情况,执行相应的字符交换策略,以求得最优解。
2202

被折叠的 条评论
为什么被折叠?



