POI2012STU-Well

xiaruize發表於2024-04-25

POI #Year2012 #二分

考慮二分答案,然後如果 \(|a_i-a_{i-1}|>mid\) ,那麼一定要提前操作掉,先把這種情況搞掉

然後考慮列舉一個位置變成 \(0\) ,在上面的操作後,可以保證 \(|a_i-a_{i-1}|\leq mid\) ,那麼這時還需要操
作的區間 \([l,r]\)\(l,r\) 都隨著 \(i\) 的增加而增加,維護這兩個端點直接算答案

// Author: xiaruize
const int N = 1e6 + 10;

int n, m;
int a[N];
int s[N], sum[N];

int check(int x)
{
	memcpy(s, a, sizeof(s));
	int cnt = 0;
	rep(i, 2, n) s[i] = min(s[i - 1] + x, s[i]);
	per(i, n - 1, 1) s[i] = min(s[i], s[i + 1] + x);
	rep(i, 1, n)
	{
		cnt += a[i] - s[i];
		sum[i] = sum[i - 1] + s[i];
	}
	for (int i = 1, l = 1, r = 1; i <= n; i++)
	{
		while (r < n && (r - i + 1) * x < s[r + 1])
			r++;
		while (l < i && (i - l) * x >= s[l])
			l++;
		if (cnt + sum[r] - sum[l - 1] - x * ((i - l) * (i - l + 1) / 2 + (r - i) * (r - i + 1) / 2) <= m)
			return i;
	}
	return -1;
}

void solve()
{
	cin >> n >> m;
	rep(i, 1, n) cin >> a[i];
	int l = 0, r = 1e9;
	pii res = {-1, -1};
	while (l < r)
	{
		int mid = l + r >> 1;
		int v = check(mid);
		if (v == -1)
			l = mid + 1;
		else
		{
			r = mid;
			res = {mid, v};
		}
	}
	cout << res.second << ' ' << res.first << endl;
}

#ifndef ONLINE_JUDGE
bool end_of_memory_use;
#endif

signed main()
{
	// freopen(".in","r",stdin);
	// freopen(".out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int testcase = 1;
	// cin >> testcase;
	while (testcase--)
		solve();
#ifndef ONLINE_JUDGE
	cerr << "Memory use:" << (&end_of_memory_use - &start_of_memory_use) / 1024.0 / 1024.0 << "MiB" << endl;
	cerr << "Time use:" << (double)clock() / CLOCKS_PER_SEC * 1000.0 << "ms" << endl;
#endif
	return 0;
}