2020ICPC·小米 网络选拔赛第二场 A-2020(二分答案)
题面:
题意:
给定一个只含有(0,1,2)的字符串,现在问你可以把字符串最多分成多少个互不相交的子序列,其中每一个子序列是(2020).
思路:
在区间([0,frac{n}{4}]) 中二分答案,对于当前的需要check的答案(mid),
我们如下进行验证:
先找到(mid)个字符( ext 2),然后对于每一个( ext 2)找到其后方最近的( ext 0) 分给它作成(20)。
然后对于每一个( ext 20)找到其后方最近的( ext 2) 分给它,作成(202)。
,然后对于每一个( ext 202)找到其后方最近的( ext 0) 分给它作成(2020)。
若能完成则返回true,否则为false。
代码:
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<=n;++i)
#define per(i,n,a) for (int i=n;i>=a;--i)
#define sz(x) ((int)(x).size())
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define lson l,mid,p<<1
#define rson mid+1,r,p<<1|1
typedef pair<int, int> pii;
#define ll long long
const int inf = 1e9;
const int mod = 1e9 + 7;
const int N = 1e6 + 10;
int n;
char s[N];
int vis[N];
int vis1[N];
int vis2[N];
int used[N];
bool check(int mid)
{
for (int i = 1; i <= n; ++i) {
vis[i] = 0;
vis1[i] = 0;
vis2[i] = 0;
used[i] = 0;
}
int num = 0;
for (int i = 1; i <= n; ++i) {
if (s[i] == '2') {
if (num < mid) {
num++;
vis[i] = 1;
used[i] = 1;
}
}
}
if (num < mid) {
return 0;
}
num = 0;
int cnt = 0;
for (int i = 1; i <= n; ++i) {
cnt += vis[i];
if (s[i] == '0' && used[i] == 0) {
if (cnt > 0 && num < mid) {
cnt--;
num++;
vis1[i] = 1;
used[i] = 1;
}
}
}
if (num < mid) {
return 0;
}
num = 0;
cnt = 0;
for (int i = 1; i <= n; ++i) {
cnt += vis1[i];
if (s[i] == '2' && used[i] == 0) {
if (cnt > 0 && num < mid) {
cnt--;
num++;
used[i] = 1;
vis2[i] = 1;
}
}
}
if (num < mid) {
return 0;
}
num = 0;
cnt = 0;
for (int i = 1; i <= n; ++i) {
cnt += vis2[i];
if (s[i] == '0' && used[i] == 0) {
if (cnt > 0 && num < mid) {
cnt--;
num++;
used[i] = 1;
}
}
}
return num >= mid;
}
int main()
{
//ios::sync_with_stdio(false);
//freopen("in","r",stdin);
while (~scanf("%d", &n)) {
scanf("%s", s + 1);
int l = 0;
int r = n / 4;
int mid;
int ans = 0;
while (l <= r) {
mid = (l + r) >> 1;
if (check(mid)) {
ans = mid;
l = mid + 1;
} else {
r = mid - 1;
}
}
printf("%d
", ans );
}
return 0;
}