CF round 789 B2 - Tokitsukaze and Good 01-String (hard version)
Tokitsukaze and Good 01-String (hard version)
贪心
两个一组分成 \(\frac n2\) 个 01 段
- 当前这一组不相同,则操作数++,并且让这一组变成和上一组一样的,段数不变
- 当前这一组相同,如果和上一组相同,段数不变;如果不相同,则段数++。更新 last
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
int n;
string s;
int main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int T;
cin >> T;
while(T--)
{
cin >> n >> s;
int x = 0, y = 0;
char last = ' ';
for (int i = 0; i < s.size(); i += 2)
{
if (s[i] != s[i+1])
x++;
else
{
if (last != s[i])
y++;
last = s[i];
}
}
cout << x << " " << max(1, y) << endl;
}
return 0;
}
操作数贪心 + 段数DP
记 \(f[i][0/1]\) 为前 i 段,最后一段是 00/11 的最小段数
贪心:若某一段需要操作两次,那这个状态就是非法的,设为 INF
其他情况dp
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
const int INF = 1e9;
int n;
string s;
int f[N][2];
int main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int T;
cin >> T;
while(T--)
{
cin >> n >> s;
s = " " + s;
int x = 0;
//初始化
if (s[1] != s[2])
{
x++;
f[2][0] = f[2][1] = 1;
}
else
{
if (s[1] == '1')
{
//贪心操作数,这一步不能操作两次,所以让这种状态不合法
f[2][0] = INF;
f[2][1] = 1;
}
else
{
f[2][0] = 1;
f[2][1] = INF;
}
}
for (int i = 4; i <= n; i += 2)
{
f[i][0] = f[i][1] = INF;
if (s[i] != s[i-1])
{
x++;
f[i][0] = min(f[i-2][0], f[i-2][1] + 1);
f[i][1] = min(f[i-2][0] + 1, f[i-2][1]);
}
else
{
//贪心操作数,当前这一段是00,就不可能让这一段变成11,所以f[i][1]非法
if (s[i] == '0')
f[i][0] = min(f[i-2][0], f[i-2][1] + 1);
else
f[i][1] = min(f[i-2][0] + 1, f[i-2][1]);
}
}
cout << x << " " << min(f[n][0], f[n][1]) << endl;
}
return 0;
}
DP
\(f[i][0/1]\) 为前 i 段,最后一段是 00/11 的 {操作数,段数},首先满足操作数最小,再满足段数最小,所以可用 pair 存储
不考虑上一个方法中:贪心:若某一段需要操作两次,那这个状态就是非法的,设为 INF
若需要操作两次,就让他操作两次,最后取 min 时得到的也是操作数最小情况下段数最小的答案
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 2e5 + 10;
const int INF = 1e9;
int n;
string s;
PII f[N][2];
int main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int T;
cin >> T;
while(T--)
{
cin >> n >> s;
s = " " + s;
int x = 0;
if (s[1] != s[2])
f[2][0] = f[2][1] = {1, 1};
else
{
if (s[1] == '1')
{
f[2][0] = {2, 1};
f[2][1] = {0, 1};
}
else
{
f[2][0] = {0, 1};
f[2][1] = {2, 1};
}
}
for (int i = 4; i <= n; i++)
{
if (s[i] != s[i-1])
{
f[i][0] = min(PII(f[i-2][0].x + 1, f[i-2][0].y), PII(f[i-2][1].x + 1, f[i-2][1].y + 1));
f[i][1] = min(PII(f[i-2][0].x + 1, f[i-2][0].y + 1), PII(f[i-2][1].x + 1, f[i-2][1].y));
}
else
{
if (s[i] == '0')
{
f[i][0] = min(PII(f[i-2][0].x, f[i-2][0].y), PII(f[i-2][1].x, f[i-2][1].y + 1));
f[i][1] = min(PII(f[i-2][0].x + 2, f[i-2][0].y + 1), PII(f[i-2][1].x + 2, f[i-2][1].y));
}
else
{
f[i][0] = min(PII(f[i-2][0].x + 2, f[i-2][0].y), PII(f[i-2][1].x + 2, f[i-2][1].y + 1));
f[i][1] = min(PII(f[i-2][0].x, f[i-2][0].y + 1), PII(f[i-2][1].x, f[i-2][1].y));
}
}
}
PII ans = min(f[n][0], f[n][1]);
cout << ans.x << " " << ans.y << endl;
}
return 0;
}