其他分享
首页 > 其他分享> > Codeforces 1680D. Dog Walking

Codeforces 1680D. Dog Walking

作者:互联网

传送门
\(\texttt{Difficulty:2400}\)

题目大意

一个长为 \(n(1\le n\le3000)\) 的序列 \(a(-10^9\le a_i\le10^9)\) ,可以用 \([-k,k](1\le k\le10^9)\) 的任意一个整数替换 \(a\) 中值为 \(0\) 的元素,求从 \(0\) 开始沿数轴移动,第 \(i\) 次移动的距离为 \(|a_i|\) (\(a_i<0\) 时向左,否则向右),并且最后能够回到 \(0\) 的过程中,能访问的整数点数量的最大值。

思路

对于整个移动过程,记在左侧能走到的最远点的值为 \(mi\) ,右侧能走到的最远点的值为 \(mx\) ,所能访问的整数点数量的最大值就是 \(mx-mi+1\) 。
在整个移动的过程中,我们采取的策略应当是先尽可能向左(右)走,再尽可能向右(左)走,最后回到 \(0\) ,这样能使得相互被抵消的部分尽可能少,于是我们可以枚举过程中的这两个分界点 \(i\), \(j\) ,假设我们先向左后向右,相当于我们在 \(i\) 处取 \(mi\) ,在 \(j\) 处取 \(mx\) ,那么我们在前 \(i\) 步的 \(0\) 中尽可能靠前填大的负数。在第 \([i+1,j]\) 步靠前填尽可能大的正数,此外还要保证最后能够回到 \(0\) ,即要保证左侧走到 \(mi\) 后右侧至少可以走回 \(0\) ,右侧走到 \(mx\) 也至少可以走回 \(0\) 。我们可以在一开始先预处理出序列 \(a\) 的前缀和以及其含有 \(0\) 的个数的前缀和,于是对于每次枚举,我们可以在 \(O(1)\) 求出满足上述条件下的 \(mi\) 与 \(mx\) ,也就是当前情况下的答案,最后将两种策略都分别枚举一遍取 \(\texttt{min}\) 即可,总的复杂度 \(O(n^2)\) 。

代码

#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
using namespace std;
using LL = long long;
using ULL = unsigned long long;
using PII = pair<int, int>;
using TP = tuple<int, int, int>;
#define all(x) x.begin(),x.end()
#define mk make_pair
//#define int LL
//#define lc p*2
//#define rc p*2+1
#define endl '\n'
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#pragma warning(disable : 4996)
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const double eps = 1e-8;
const LL MOD = 1000000007;
const LL mod = 998244353;
const int maxn = 3010;

LL N, K, A[maxn], S[maxn], SS[maxn];

void solve()
{
	LL sum = 0;
	for (int i = 1; i <= N; i++)
		sum += A[i], S[i] = S[i - 1] + (A[i] == 0), SS[i] = SS[i - 1] + A[i];
	LL lst = 0LL - sum, ans = 1;
	if (lst > S[N] * K || lst < S[N] * -K)
	{
		cout << -1 << endl;
		return;
	}
	for (int i = 0; i <= N; i++)
	{
		for (int j = i + 1; j <= N; j++)
		{
			LL sub = min(K * S[i], K * (S[N] - S[i]) - lst), mi = SS[i] - sub;
			LL add = min(K * (S[j] - S[i]), K * (S[N] - S[j]) + lst + sub), mx = SS[j] - sub + add;
			ans = max(ans, mx - mi + 1);
		}
	}
	for (int i = 0; i <= N; i++)
	{
		for (int j = i + 1; j <= N; j++)
		{
			LL add = min(K * S[i], K * (S[N] - S[i]) + lst), mx = SS[i] + add;
			LL sub = min(K * (S[j] - S[i]), K * (S[N] - S[j]) - lst + add), mi = SS[j] - sub + add;
			ans = max(ans, mx - mi + 1);
		}
	}
	cout << ans << endl;
}

int main()
{
	IOS;
	cin >> N >> K;
	for (int i = 1; i <= N; i++)
		cin >> A[i];
	solve();

	return 0;
}

标签:Walking,const,LL,mi,Codeforces,using,mx,1680D,define
来源: https://www.cnblogs.com/Prgl/p/16313049.html