Live2D

AGC044E Random Pawn 题解

link

Solution

首先我们考虑 \(B_i=0\) 的情况怎么解决,可以发现的是,我们设 \(f_i\) 表示从 \(i\) 出发的最大期望贡献,当 \(A_i\) 为最大值时 \(f_i=A_i\),否则如果我们要停止,为 \(A_i\),不停止为 \((f_{i-1}+f_{i+1})/2\)

设相邻两个停止点为 \(u,v\),那么对于 \(i\in [u,v]\),则有:

\[f_i=((i-u)\times A_u+(v-i)\times A_v)/(v-u) \]

不难发现的是,这玩意的和最大就是这个 \((u,A_u)\)\((v,A_v)\) 围成的梯形最大,所以我们这些停止点选上凸壳即可。

考虑存在 \(B_i\) 的情况,我们可以通过引入参数 \(C_i\) 来抵消掉,具体来说,我们设 \(P_i=f_i-C_i\),那么我们就有:

\[P_i=(P_{i-1}+P_{i+1})/2-B_i+(C_{i-1}+C_{i+1})/2-C_i=(P_{i-1}+P_{i+1})/2 \]

所以我们就存在递推式

\[C_{i+1}=2\times (C_i+B_i)-C_{i-1} \]

然后就做完了。

Code

#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define int long long
#define MAXN 2000005

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}

int n,tp,a[MAXN],b[MAXN],C[MAXN],na[MAXN],nb[MAXN],sta[MAXN];

signed main(){
	read (n);
	for (Int i = 1;i <= n;++ i) read (a[i]);
	for (Int i = 1;i <= n;++ i) read (b[i]);
	int pos = max_element (a + 1,a + n + 1) - a,c = 0;
	for (Int i = pos;i <= n;++ i) na[++ c] = a[i],nb[c] = b[i];
	for (Int i = 1;i <= pos - 1;++ i) na[++ c] = a[i],nb[c] = b[i];
	for (Int i = 1;i <= n;++ i) a[i] = na[i],b[i] = nb[i];a[n + 1] = a[1];
//	for (Int i = 1;i <= n + 1;++ i) cout << a[i] << " ";cout << endl;
//	for (Int i = 1;i <= n;++ i) cout << b[i] << " ";cout << endl;
	for (Int i = 2;i <= n;++ i) C[i + 1] = 2 * (C[i] + b[i]) - C[i - 1];
	for (Int i = 1;i <= n + 1;++ i){
		a[i] -= C[i];
		while (tp > 1 && (a[sta[tp]] - a[sta[tp - 1]]) * (i - sta[tp]) <= (a[i] - a[sta[tp]]) * (sta[tp] - sta[tp - 1])) -- tp;
		sta[++ tp] = i;
	}
	int ans = 0; 
	for (Int i = 2;i <= tp;++ i) c = sta[i] - sta[i - 1],ans += a[sta[i - 1]] * (c + 1) + a[sta[i]] * (c - 1);
	for (Int i = 1;i <= n;++ i) ans += 2 * C[i];
	printf ("%.12f\n",ans / (2.0 * n));
	return 0;
}
posted @ 2022-01-25 17:42  Dark_Romance  阅读(51)  评论(0编辑  收藏  举报