CodeForces 1942F Farmer John's Favorite Function

洛谷传送门

CF 传送门

考虑一些复杂度带根号的做法。

考虑分块,对于一个块,我们需要处理出一个数经过这个块会变成哪个数。以下假设块长 \(\ge 10\)(最后一个块块长可能 \(< 10\),暴力处理即可)。

观察这个递推式 \(f_i = \left\lfloor\sqrt{f_{i - 1} + a_i}\right\rfloor\),发现对于一开始传进去 \(0\) 和传进去 \(10^{18}\),经过足够多(\(\ge 10\) 个,应该能更少)的数,最后得到的 \(f_i\) 最多相差 \(1\)。证明显然,因为有一个根号,每次会让 \(\Delta\) 开根,进行 \(\log \log V\)\(\Delta\) 就会变成 \(1\)

设传进去 \(0\) 得到 \(x\),传进去 \(10^{18}\) 得到 \(y\)。若 \(x = y\) 那么已经完成了。否则 \(x + 1 = y\),我们需要求出这个分界点,即求出 \(z\) 使得传进去 \(z\) 得到 \(x\),传进去 \(z + 1\) 得到 \(y\)。考虑有 \(f_i^2 \le f_{i - 1} + a_i \le (f_i + 1)^2 - 1\),所以我们用 \(x\) 倒推,倒推的同时维护 \(f_i\) 的上界即可。

修改就重构所在块,询问扫一遍所有块,维护经过一段前缀的块后的 \(f_i\) 的值即可。

时间复杂度 \(O(n + m \sqrt{n})\)

code
// Problem: F. Farmer John's Favorite Function
// Contest: Codeforces - CodeTON Round 8 (Div. 1 + Div. 2, Rated, Prizes!)
// URL: https://codeforces.com/contest/1942/problem/F
// Memory Limit: 256 MB
// Time Limit: 5000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 200100;

ll n, m, a[maxn], b[maxn], c[maxn], B, bel[maxn], L[maxn], R[maxn];

inline void build(int t) {
	ll x = 0, y = 1.1e18;
	for (int i = L[t]; i <= R[t]; ++i) {
		x = sqrtl(x + a[i]);
		y = sqrtl(y + a[i]);
	}
	b[t] = x;
	if (x == y) {
		c[t] = 1e18;
		return;
	}
	for (int i = R[t]; i >= L[t]; --i) {
		x = min((ll)2e9, (x + 1) * (x + 1) - 1 - a[i]);
	}
	c[t] = x;
}

void solve() {
	scanf("%lld%lld", &n, &m);
	B = max(10LL, (ll)sqrt(n));
	for (int i = 1; i <= n; ++i) {
		scanf("%lld", &a[i]);
		bel[i] = (i - 1) / B + 1;
		if (!L[bel[i]]) {
			L[bel[i]] = i;
		}
		R[bel[i]] = i;
	}
	for (int i = 1; i <= bel[n]; ++i) {
		build(i);
	}
	while (m--) {
		ll x, y;
		scanf("%lld%lld", &x, &y);
		a[x] = y;
		build(bel[x]);
		x = 0;
		for (int i = 1; i < bel[n]; ++i) {
			x = b[i] + (x > c[i]);
		}
		for (int i = L[bel[n]]; i <= R[bel[n]]; ++i) {
			x = sqrtl(x + a[i]);
		}
		printf("%lld\n", x);
	}
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

posted @ 2024-04-04 22:03  zltzlt  阅读(16)  评论(0编辑  收藏  举报