题解:CF643C Levels and Regions

思路:

第一次完全自己做出期望题,写题解纪念之。

首先,每个位置的期望要推出来,需要一点数列知识。

\(a=\sum_{x=l_i}^it_x,b=t_i\),则 \(E_i(X)=b\sum_{i=1}^{\infty}{i(a-b)^{i-1}\over a^i}\)

我们设数列 \(c_{n}={n(a-b)^{n-1}\over a^n}\)\(S_n\)\(c_n\) 的前 \(n\) 项和,\(S_n={1\over a}+{2(a-b)\over a^2}+{3(a-b)^2\over a^3}+...+{n(a-b)^{n-1}\over a^n}\)

\({a-b\over a}S_{n}={(a-b)\over a^2}+{2(a-b)^2\over a^3}+...+{(n-1)(a-b)^{n-1}\over a^n}+{n(a-b)^n\over a^n}\),两式相减得

\[\begin{align}{b\over a}S_{n}&={1\over a}+{(a-b)\over a^2}+{(a-b)^2\over a^3}+...+{(a-b)^{n-1}\over a^n}-{n(a-b)^n\over a^{n+1}}\\&=\{{{1\over a}[1-({a-b\over a})^n]\over 1-{a-b \over a}}-{n(a-b)^n\over a^{n+1}}\}\end{align} \]

再化一下简,得 \(S_n={a[1-({a-b\over a})^n]\over b^2}-n({a-b\over a})^n\),而 \({a-b\over a}<1\),则当 \(n\rightarrow \infty\)\(({a-b\over a})^n=0\),所以 \(S_n={a\over b^2}\)

那么期望 \(E_i(X)={a\over b}\),即 \(E_i(X)={\sum_{x=l_i}^it_x\over t_i}={\sum_{x=1}^it_x\over t_i}-{1\over t_i}\sum_{x=1}^{l_i}t_i\)

那么我们可以通过 \(t_i\) 的前缀和,\({\sum_{x=l_i}^it_x\over t_i}\) 的前缀和以及 \({1\over t_i}\) 的前缀和 \(O(1)\) 求出区间 \([l,r]\) 的期望,分别记为 \(suma_i,sumb_i,sumc_i\)

定义 \(f_{i,j}\) 为前 \(i\) 个位置分成了 \(j\) 段,期望的最小值。

我们定义一个区间的期望和为 \(w(l,r)=sumb_r-sumb_{l-1}-suma_{l-1}\times(sumc_{r}-sumc_{l-1})\)

\(f_{i,j}=\min(f_{k,j-1}+w(k+1,i))\)

这里证明 \(w(l,r+1)+w(l+1,r)≥w(l,r)+w(l+1,r+1)\)

移项得 \(w(l,r+1)-w(l,r)\ge w(l+1,r+1)-w(l+1,r)\),代入得 \(sumb_{r+1}-sumb_{r}-suma_{l-1}\times(sumc_{r+1}-sumc_{r})\ge sumb_{r+1}-sumb_{r}-suma_{l}\times(sumc_{r+1}-sumc_{r})\)

显然有 \(suma_{l-1}\le suma_l\),故转移方程满足决策单调性,可以分治求解。

时间复杂度为 \(O(nk\log n)\)

code

const int N=2e5+10;
double f[N][51];
int n,k;
ll a[N],suma[N];
double b[N],c[N],sumb[N],sumc[N];
int now=0;
void solve(int l,int r,int lt,int rt)
{
	int mid=(l+r)>>1,L=max(0,lt),R=min(rt,mid-1);
	double Res=1e18;int pos=0;
	for(int i=L;i<=R;i++)
	{
		double tmp=f[i][now-1]+sumb[mid]-sumb[i]-suma[i]*(sumc[mid]-sumc[i]);
		if(tmp<Res) Res=tmp,pos=i;
	}
	f[mid][now]=Res;
	if(l==r) return;
	solve(l,mid,lt,pos),solve(mid+1,r,pos,rt);
}
int main()
{
	read(n,k);
	for(int i=1;i<=n;i++) 
	{
		read(a[i]),suma[i]=suma[i-1]+a[i];
		c[i]=1.0/a[i],sumc[i]=sumc[i-1]+c[i];
		b[i]=1.0*suma[i]/a[i],sumb[i]=sumb[i-1]+b[i];
	}
	for(int i=0;i<=n;i++)
		for(int j=0;j<=k;j++) f[i][j]=1e18;
	f[0][0]=0;
	for(now=1;now<=k;now++) solve(0,n,0,n);
	write(f[n][k]);
    return 0;
}
posted @ 2024-11-08 14:53  EityDawn  阅读(32)  评论(0)    收藏  举报