CF1428F Fruit Sequences 题解

发布时间 2023-11-10 16:44:19作者: mfeitveer

使用了一种和大多数题解不同的做法。

虽然是带 \(log\) 的。

思路

首先考虑如何求一个固定左端点的答案。

我们发现,每个答案会随着右端点的递增单调不降。

而每个答案在增加时会形成若干个区间。

例如:

11101010111111

我们答案增加的区间即为:

11100000000111

可以发现,这个区间就是不断往前找到第一个长度大于当前极长连续段的极长连续段。

那么我们对于每个点统计出往后的全一极长连续段的长度。

就可以将所有询问简单的用堆维护。

Code

/**
 * @file 1428F.cpp
 * @author mfeitveer
 * @date 2023-11-10
 * 
 * @copyright Copyright (c) 2023
 * 
 */
#include <bits/stdc++.h>
using namespace std;

#define x first
#define y second
#define mp(x, y) make_pair(x, y)
#define fro(i, x, y) for(int i = (x);i <= (y);i++)
#define pre(i, x, y) for(int i = (x);i >= (y);i--)
#define dbg cerr << "Line " << __LINE__ << ": "
#define EVAL(x) #x " = " << (x)

typedef int64_t i64;
typedef uint32_t u32;
typedef uint64_t u64;
typedef __int128_t i128;
typedef __uint128_t u128;
typedef pair<int, int> PII;

bool ed;

const int N = 1000010;
const int mod = 998244353;

int n, m, a[N], sz[N], len[N], sum[N];
string s;

inline void solve()
{
	cin >> n >> s;
	fro(i, 1, n) a[i] = s[i - 1] - '0';
	fill(sz + 1, sz + n + 1, 1);
	fro(i, 1, n) if(a[i])
	{
		int j = i; while(a[j + 1]) j++;
		fro(k, i, j) len[k] = j - k + 1; i = j;
	}
	priority_queue<PII, vector<PII>, greater<PII>> q;
	fro(i, 1, n)
	{
		while(!q.empty() && q.top().x < len[i])
		{
			int x = q.top().y;
			sum[i + len[x]] += sz[x];
			sum[i + len[i]] -= sz[x];
			sz[i] += sz[x], q.pop();
		}
		q.emplace(len[i], i);
		sum[i] += 1, sum[i + len[i]] -= 1;
	}
	i64 ans = 0, num = 0, all = 0;
	fro(i, 1, n) num += sum[i], all += num, ans += all;
	cout << ans << "\n";
}

bool st;

signed main()
{
	ios::sync_with_stdio(0), cin.tie(0);
	double Mib = fabs((&ed-&st)/1048576.), Lim = 250;
	assert(Mib<=Lim), cerr << " Memory: " << Mib << "\n";
	solve();
	return 0;
}