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