Problem - 1809D - Codeforces
给定一个仅由字符0和/或1组成的二进制字符串s。
您可以对此字符串执行几个操作(可能为零)。有两种类型的操作:
选择两个相邻的元素并交换它们。为了执行此操作,您需要支付1012硬币;
选择字符串中的任何元素并删除它。为了执行此操作,您需要支付1012 + 1个硬币。
您的任务是计算将字符串s排序为非递减顺序(即将s转换为s1≤s2≤⋯≤sm,其中m是应用所有操作后字符串的长度)所需的最小硬币数量。空字符串也被认为是已按非递减顺序排序的。
输入
第一行包含一个整数t(1≤t≤104)——测试用例数。
每个测试用例的唯一行包含字符串s(1≤|s|≤3⋅105),仅由字符0和/或1组成。
所有给定字符串的长度之和不超过3⋅105。
输出
对于每个测试用例,输出一个整数——将字符串s排序为非递减顺序所需的最小硬币数量。
Example
Input
Copy
6
100
0
0101
00101101
1001101
11111
Output
Copy
1000000000001 0 1000000000000 2000000000001 2000000000002 0
在第一个例子中,您需要删除第1个元素,使字符串变为00。
在第二个例子中,字符串已经排序。
在第三个例子中,您需要交换第2和第3个元素,使字符串变为0011。
在第四个例子中,您需要交换第3和第4个元素,使字符串变为00011101,然后删除第7个元素,使字符串变为0001111。
在第五个例子中,您需要删除第1个元素,使字符串变为001101,然后删除第5个元素,使字符串变为00111。
在第六个例子中,字符串已经排序。
题解:
我们可以枚举从哪一个位置开始,左边全为0,右边全为1
如果交换的次数超过1,是不如删除的
只有这种情况才会进行交换操作10
我们利用前缀和记录0出现的次数
对于每个位置,看多少0和1要被删除
对于交换的操作,其实最多就只有一次,看看位置如果符合减1即可
#include <cstdio>
#include <cstring>
#include <algorithm>
#include<iostream>
#include<vector>
#include<set>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
#define int long long
typedef pair<int,int> PII;
typedef unsigned long long ULL;
const int N = 4e5 + 10;
int mod = 1e9 + 7;
int cnt[N];
void solve()
{
string s;
cin >> s;
int n = s.size();
s = " " + s;
for(int i = 1;i <= n;i++)
{
cnt[i] = cnt[i - 1] + (s[i] == '0');
}
int ans = 1e18;
for(int i = 0;i <= n;i++)
{
int x = i - cnt[i];
int y = cnt[n] - cnt[i];
if(i != 0&&s[i] == '0'&&s[i - 1] == '1')
{
ans = min(ans,(int)(x+y)*(int)(1e12 + 1) - 1);
}
else
{
ans = min(ans,(int)(x + y)*(int)(1e12 + 1));
}
}
cout << ans <<"\n";
}
signed main()
{
ios::sync_with_stdio(0 );
cin.tie(0);cout.tie(0);
int t = 1;
cin >> t;
while(t--)
{
solve();
}
}