[atAGC044E]Random Pawn
记$ans_{i}$为初始位于$i$的答案,显然有$ans_{i}=\max(a_{i},\frac{ans_{i-1}+ans_{i+1}}{2}-b_{i})$
通过旋转,不妨假设$\forall 1\le i<n,a_{n}\ge a_{i}$,并定义$a_{0}=a_{n}$
此时,显然有$ans_{0}=ans_{n}=a_{0}$,即首尾并不需要转移,问题变为了一条链
构造一组$\{c_{i}\}$,记$s_{i}=ans_{i}-c_{i}$,代入可得$s_{i}=\max(a_{i}-c_{i},\frac{(s_{i-1}+c_{i-1})+(s_{i+1}+c_{i+1})}{2}-(b_{i}+c_{i}))$
若$\{c_{i}\}$满足$\frac{c_{i-1}+c_{i+1}}{2}=b_{i}+c_{i}$,那么上式也即$s_{i}=\max(a_{i}-c_{i},\frac{s_{i-1}+s_{i+1}}{2})$
注意到此时的$s_{i}$即$(i,a_{i}-c_{i})$构成的上凸包中$i$处的值,直接计算即可,最后再加上$c_{i}$即得到$ans_{i}$
关于如何使$c_{i}$满足该式子,注意到$c_{0}$和$c_{n}$是任意的,直接令$c_{0}=c_{1}=0$并递推即可
时间复杂度为$o(n)$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 200005 4 #define ll long long 5 #define ld long double 6 int n,bb[N],b[N],st[N]; 7 ll aa[N],a[N],c[N]; 8 ld ans; 9 ld get_k(int x,int y){ 10 return 1.0*(a[x]-a[y])/(x-y); 11 } 12 int main(){ 13 scanf("%d",&n); 14 for(int i=1;i<=n;i++)scanf("%lld",&aa[i]); 15 for(int i=1;i<=n;i++)scanf("%d",&bb[i]); 16 for(int i=1;i<=n;i++)aa[0]=max(aa[0],aa[i]); 17 for(int i=1;i<=n;i++) 18 if (aa[i]==aa[0]){ 19 for(int j=1;j<=n;j++){ 20 a[(j+n-i-1)%n+1]=aa[j]; 21 b[(j+n-i-1)%n+1]=bb[j]; 22 } 23 break; 24 } 25 a[0]=a[n],c[0]=c[1]=0; 26 for(int i=2;i<=n;i++)c[i]=2*(b[i-1]+c[i-1])-c[i-2]; 27 for(int i=0;i<=n;i++)a[i]-=c[i]; 28 for(int i=0;i<=n;i++){ 29 while ((st[0]>1)&&(get_k(st[st[0]-1],st[st[0]])<get_k(st[st[0]-1],i)))st[0]--; 30 st[++st[0]]=i; 31 } 32 for(int i=1;i<st[0];i++) 33 for(int j=st[i]+1;j<=st[i+1];j++)ans+=get_k(st[i],st[i+1])*(j-st[i])+a[st[i]]+c[j]; 34 printf("%.10Lf\n",ans/n); 35 return 0; 36 }