ARC117 - Gateau

ARC117 - Gateau

题目大意:给定一个长度为 \(2n\) 的非负环序列 \(x_0,x_1,\cdots x_{2n-1}\) ,以及 \(2n\) 条限制,每条都是

\(\forall A_i,\sum_{j=0}^{n-1} x_{i+j\mod 2n}\ge A_i\)

求最小化 \(\sum x_i\)


\[ \ \]

转化为前缀和作差之后,令人联想到差分约束,但是难以处理跨过环末的限制

于是二分答案 \(s=x_{2n-1}\) ,建立最长路图

\(\forall i<n,dis_{i+n}\ge dis_{i}+A_i\)

\(\forall i\ge n,dis_{i-n}\ge dis_{i}+A_i-s\)

\(\forall i<2n-1,dis_{i+1}\leq dis_i\)

那么无解的条件就是:存在正环或者求得 \(dis_{2n-1}>s\)

自然无法直接通过 \(\text{SPFA}\) 来跑。。。

考虑所有的边构成了一条 \(0-2n-1\) 的零链 和若干极小的二元环

如果二元环出现正环则无解,否则任意一条最长路路径总是可以描述为

\(i<j<n , i(+n)\rightarrow j(+n)\)

在中间点 \(k\) 可以选择花费0的代价向后走,或者

\(k<n:k\rightarrow k+n,cost=A_k\)

\(k\ge n:k\rightarrow k-n,cost=A_k-s\)

也就是在 \(k,k+n\) 之间反复横跳,由此发现一条路径就是

\(0-n-1\) 进行扫描,并且允许中间 \(\pm n\) 横跳

(当然这里漏掉了一个特殊边,即 \(dis_{n}\ge dis_{n-1}\) ,这是构成环的边)

这样写出一个变种的 \(\text{Bellman Ford}\) ,由于图的特殊性,只需要常数轮即可确定正环

具体的,当图上不存在正环时,扫描最多经过一次环就会停止更新

也就是这样横跳的扫描更新只会进行常数轮(2轮?)

如果若干轮后依然在更新,说明出现了正环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef pair <int,int> Pii;
#define reg register
#define mp make_pair
#define pb push_back
#define Mod1(x) ((x>=P)&&(x-=P))
#define Mod2(x) ((x<0)&&(x+=P))
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
int cmax(int &a,int b){ return a<b?a=b,1:0; }

char IO;
template <class T=int> T rd(){
T s=0; int f=0;
while(!isdigit(IO=getchar())) f|=IO=='-';
do s=(s<<1)+(s<<3)+(IO^'0');
while(isdigit(IO=getchar()));
return f?-s:s;
}

const int N=3e5+10,INF=1e9+10;

int n;
int A[N],dp[N];

int Check(int s) {
rep(i,0,n-1) if(A[i]+A[i+n]-s>0) return 0;
rep(i,0,n*2-1) dp[i]=0;
dp[n*2-1]=s;
int f=0;
rep(k,0,5) {
f=0;
rep(i,0,n-1) {
f|=cmax(dp[i+n],dp[i]+A[i]);
f|=cmax(dp[i],dp[i+n]+A[i+n]-s);
if(i<n-1) {
f|=cmax(dp[i+1],dp[i]);
f|=cmax(dp[i+n+1],dp[i+n]);
}
}
f|=cmax(dp[n],dp[n-1]);
}
if(f || dp[n*2-1]>s) return 0;
return 1;
}

int main() {
n=rd();
rep(i,0,n*2-1) A[i]=rd();
int res=-1;
for(int l=0,r=1.05e9,mid;l<=r;) Check(mid=(l+r)>>1)?r=mid-1,res=mid:l=mid+1;
printf("%d\n",res);
}