USACO22FEB Cow Camp G

P8190 [USACO22FEB] Cow Camp G

题目大意

贝西在一道题上骗分,有 t t t个数据点,第一个数据点为样例。贝西一定能过第一个数据点,她通过其余数据点的概率都是 1 2 \dfrac 12 21。她可以交 k k k次代码,她最终期望得分的最大值是多少。

2 ≤ t ≤ 1 0 3 , 1 ≤ k ≤ 1 0 9 2\leq t\leq 10^3,1\leq k\leq 10^9 2t103,1k109


题解

不考虑样例,将 t = t − 1 t=t-1 t=t1,样例的贡献在最后计算。

首先考虑单次提交的期望得分,通过 i i i个测试点的概率为 C t i 2 t \dfrac{C_t^i}{2^t} 2tCti,那么单次提交的期望得分为 ∑ i = 0 t i × C t i 2 t = t 2 \sum\limits_{i=0}^ti\times \dfrac{C_t^i}{2^t}=\dfrac t2 i=0ti×2tCti=2t

f n f_n fn表示交 n n n次以内的最大期望得分,则由上文得 f 1 = t 2 f_1=\dfrac t2 f1=2t,当 n > 1 n>1 n>1时,

f n = ∑ i = 1 t max ⁡ ( f n − 1 , i ) × C t i f_n=\sum\limits_{i=1}^t\max(f_{n-1},i)\times C_t^i fn=i=1tmax(fn1,i)×Cti

为什么不呢?如果当前得分小于等于之后的期望得分,那么就继续;否则,立即停下。

将这个式子根据 max ⁡ \max max拆成两部分得

f n = f n − 1 × ∑ i = 1 ⌊ f n − 1 ⌋ C t i + ∑ i = ⌊ f n − 1 ⌋ + 1 t i × C t i f_n=f_{n-1}\times \sum\limits_{i=1}^{\lfloor f_{n-1}\rfloor}C_t^i+\sum\limits_{i=\lfloor f_{n-1}\rfloor+1}^ti\times C_t^i fn=fn1×i=1fn1Cti+i=fn1+1ti×Cti

其中 ∑ i = 1 ⌊ f n − 1 ⌋ C t i \sum\limits_{i=1}^{\lfloor f_{n-1}\rfloor}C_t^i i=1fn1Cti ∑ i = ⌊ f n − 1 ⌋ + 1 t i × C t i \sum\limits_{i=\lfloor f_{n-1}\rfloor+1}^ti\times C_t^i i=fn1+1ti×Cti都可以用前缀和预处理求出。

这样,我们就可以 O ( k ) O(k) O(k)来求 f k f_k fk,但是 k k k很大,依然不行。

我们可以用矩阵快速幂。

[ ∑ i = 1 ⌊ f n − 1 ⌋ C t i ∑ i = ⌊ f n − 1 ⌋ + 1 t i × C t i 0 1 ] [ f n − 1 1 ] = [ f n 1 ] \left[ \begin{matrix} \sum\limits_{i=1}^{\lfloor f_{n-1}\rfloor}C_t^i & \sum\limits_{i=\lfloor f_{n-1}\rfloor+1}^ti\times C_t^i \\ \\ 0 & 1 \end{matrix} \right] \left[ \begin{matrix} f_{n-1} \\ 1 \end{matrix} \right]= \left[ \begin{matrix} f_n \\ 1 \end{matrix} \right] i=1fn1Cti0i=fn1+1ti×Cti1 [fn11]=[fn1]

⌊ f n − 1 ⌋ \lfloor f_{n-1}\rfloor fn1不变时,我们才能用矩阵快速幂,而 ⌊ f n − 1 ⌋ \lfloor f_{n-1}\rfloor fn1最多有 T + 1 T+1 T+1种取值,所以用分段快速幂即可。

时间复杂度为 O ( t 2 + 2 3 t log ⁡ 2 k ) O(t^2+2^3t\log^2 k) O(t2+23tlog2k)

code

#include
using namespace std;
int t,k;
double wf,s[1005],st[1005],yh[1005];
struct matrix{
	double a[2][2];
	matrix operator*(const matrix ax)const{
		matrix cx;
		for(int i=0;i<=1;i++){
			for(int j=0;j<=1;j++){
				cx.a[i][j]=0;
				for(int k=0;k<=1;k++){
					cx.a[i][j]+=a[i][k]*ax.a[k][j];
				}
			}
		}
		return cx;
	}
};
matrix mi(matrix t,int v){
	matrix re;
	re.a[0][0]=re.a[1][1]=1;
	re.a[0][1]=re.a[1][0]=0;
	while(v){
		if(v&1) re=re*t;
		v>>=1;t=t*t;
	}
	return re;
}
bool gt(int x){
	matrix w,re;
	w.a[0][0]=s[x];w.a[0][1]=st[x+1];
	w.a[1][0]=0;w.a[1][1]=1;
	re=mi(w,k);
	if(re.a[0][0]*wf+re.a[0][1]<x+1){
		wf=re.a[0][0]*wf+re.a[0][1];
		return 0;
	}
	int l=0,r=k,mid;
	while(l<=r){
		mid=l+r>>1;
		re=mi(w,mid);
		if(re.a[0][0]*wf+re.a[0][1]>=x+1) r=mid-1;
		else l=mid+1;
	}
	k-=r+1;
	re=mi(w,r+1);
	wf=re.a[0][0]*wf+re.a[0][1];
	return 1;
}
int main()
{
	scanf("%d%d",&t,&k);--t;--k;
	wf=1.0*t/2;
	yh[0]=1;
	for(int i=1;i<=t;i++) yh[i]=0;
	for(int i=1;i<=t;i++){
		for(int j=i;j>=1;j--){
			yh[j]=(yh[j-1]+yh[j])/2;
		}
		yh[0]/=2;
	}
	for(int i=0;i<=t;i++) s[i]=s[i-1]+yh[i];
	for(int i=t;i>=0;i--){
		st[i]=st[i+1]+1.0*i*yh[i];
	}
	for(int v=int(wf);v<=t;v=int(wf)){
		if(!gt(v)) break;
	}
	printf("%.8f",1+wf);
	return 0;
}

你可能感兴趣的:(题解,题解,c++)