题解 [ARC117F] Gateau
首先以为是贪心
然后发现是 ARC F 题不太能直接贪
发现这是个环很难处理
尝试断成链又发现限制条件不好挪到链上
于是题解指出关键性质是限制条件恰好长为 \(n\)
那么二分答案一下,总草莓数是固定的,一个半环上至少的限制就变成了另外半环上至多的限制
为了与题解同步方便,令 \(s_i=\sum\limits_{j=0}^{i-1}d_i\),那么现在的限制条件就是 \(\forall i, s_{i+n}-s_i\in[l_i, r_i]\)
然后要怎么满足这个限制呢?
看起来很贪心,但是如果我们贪心确定 \(s_{0, \cdots 2n-1}\) 的话,会发现因为 \(s_{i+n}\) 是未知的而无从判断条件是否满足
但再仔细思考发现 \(s_i\) 与 \(s_{i+n}\) 之间的关联似乎仅在于 \(s_i\leqslant s_{i+1}\) 和刚才的 \(\in[l_i, r_i]\) 限制
那么似乎可以尝试提前确定 \(s_n\) 的取值
这样的话 \(\forall i\in [0, n-1]\),只需要贪心调整 \(s\) 的值使其满足限制,最后看是否满足 \(s_{n-1}\leqslant s_n\and s_{2n-1}\leqslant mid\) 就可以了
那么猜测可行性关于 \(s_n\) 的取值有单调性
试着证一下:
\(s_n\) 越大,差值 \(\leqslant\) 一个数的限制可以同步增大 \(s_0\) 解决
而此时差值 \(\geqslant\) 一个数的限制更容易满足了
所以有单调性
那么二分出使 \(s_{2n-1}\leqslant mid\) 的最大的 \(s_n\) check 一下就好了
复杂度 \(O(n\log^2 n)\)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 300010
#define fir first
#define sec second
#define ll long long
#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n;
int a[N], l[N], r[N], lim;
pair<int, int> check(int mid, int sum) {
int x=0, y=mid;
for (int i=0; i<n; ++i) {
if (y-x<l[i]) y+=l[i]-y+x;
else if (y-x>r[i]) x+=y-x-r[i];
}
return {x, y};
}
bool check(int sum) {
for (int i=0; i<n; ++i) l[i]=a[i];
for (int i=n; i<(n<<1); ++i) r[i-n]=sum-a[i];
for (int i=0; i<n; ++i) if (l[i]>r[i]) return 0;
int l=0, r=sum, mid;
while (l<=r) {
mid=(l+r)>>1;
if (check(mid, sum).sec<=sum) l=mid+1;
else r=mid-1;
}
return check(l-1, sum).fir<=l-1;
}
signed main()
{
n=read();
for (int i=0; i<(n<<1); ++i) lim=max(lim, a[i]=read());
int l=0, r=lim<<1, mid;
while (l<=r) {
mid=(l+r)>>1;
if (check(mid)) r=mid-1;
else l=mid+1;
}
printf("%lld\n", r+1);
return 0;
}