题面
首先有一个很简单的想法,设
f
i
f_i
fi 为从第
i
i
i 个位置出发的最大收益,决策得到:
f
i
=
max
(
A
i
,
1
2
(
f
i
−
1
+
f
i
+
1
)
−
B
i
)
f_i=\max(A_i,\frac{1}{2}(f_{i-1}+f_{i+1})-B_i)
fi=max(Ai,21(fi−1+fi+1)−Bi)
这里的下标均在模
n
n
n 意义下。由于收益只会来自于
A
A
A,所以对于
A
A
A 最大的
i
i
i 一定有
f
i
=
A
i
f_i=A_i
fi=Ai。由此可以将环拆为链。
当
B
i
=
0
B_i=0
Bi=0 时,于USACO的平衡木那道题类似。于是构造一个数列
C
C
C,得到数列
g
g
g,满足
g
i
=
f
i
−
C
i
g_i=f_i-C_i
gi=fi−Ci。这样,当
i
i
i 不为最优决策点时,有
g
i
=
1
2
(
g
i
−
1
+
g
i
+
1
)
=
1
2
(
f
i
−
1
+
f
i
+
1
)
−
B
i
−
C
i
g_i=\frac{1}{2}(g_{i-1}+g_{i+1})=\frac{1}{2}(f_{i-1}+f_{i+1})-B_i-C_i
gi=21(gi−1+gi+1)=21(fi−1+fi+1)−Bi−Ci。将
f
f
f 展开得到:
C
i
+
1
+
C
i
−
1
=
2
(
B
i
+
C
i
)
C_{i+1}+C_{i-1}=2(B_i+C_i)
Ci+1+Ci−1=2(Bi+Ci)
令
C
0
=
C
1
=
0
C_0=C_1=0
C0=C1=0 即可算出
C
C
C。最后用平衡木的方法求上凸壳即可。
时间复杂度
O
(
n
)
O(n)
O(n),空间复杂度
O
(
n
)
O(n)
O(n)
#include<stdio.h>
#define R register int
#define L long long
#define N 200001
L a[N],d[N],c[N];
int b[N],e[N],q[N];
int main(){
int n,maxI=0,tail=0;
scanf("%d",&n);
for(R i=1;i<=n;i++){
scanf("%lld",d+i);
if(d[maxI]<d[i]){
maxI=i;
}
}
for(R i=1;i<=n;i++){
scanf("%d",e+i);
}
for(R i=maxI;i<=n;i++){
a[i-maxI]=d[i];
b[i-maxI]=e[i];
}
for(R i=1;i<=maxI;i++){
a[i+n-maxI]=d[i];
b[i+n-maxI]=e[i];
}
c[1]=0;
L ans=0;
for(R i=2;i<=n;i++){
c[i]=(c[i-1]+b[i-1]<<1)-c[i-2];
a[i]-=c[i];
}
for(R i=2;i!=n;i++){
ans+=c[i]<<1;
}
for(R i=1;i<=n;i++){
while(tail!=0&&(a[q[tail-1]]-a[q[tail]])*(q[tail]-i)<=(a[q[tail]]-a[i])*(q[tail-1]-q[tail])){
tail--;
}
tail++;
q[tail]=i;
}
for(R i=0;i!=tail;i++){
ans+=(q[i+1]-q[i]+1)*(a[q[i]]+a[q[i+1]])-(a[q[i+1]]<<1);
}
printf("%.19lf",.5*ans/n);
return 0;
}