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 2≤t≤103,1≤k≤109
不考虑样例,将 t = t − 1 t=t-1 t=t−1,样例的贡献在最后计算。
首先考虑单次提交的期望得分,通过 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=0∑ti×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=1∑tmax(fn−1,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=fn−1×i=1∑⌊fn−1⌋Cti+i=⌊fn−1⌋+1∑ti×Cti
其中 ∑ i = 1 ⌊ f n − 1 ⌋ C t i \sum\limits_{i=1}^{\lfloor f_{n-1}\rfloor}C_t^i i=1∑⌊fn−1⌋Cti和 ∑ 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=⌊fn−1⌋+1∑ti×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=1∑⌊fn−1⌋Cti0i=⌊fn−1⌋+1∑ti×Cti1 [fn−11]=[fn1]
当 ⌊ f n − 1 ⌋ \lfloor f_{n-1}\rfloor ⌊fn−1⌋不变时,我们才能用矩阵快速幂,而 ⌊ f n − 1 ⌋ \lfloor f_{n-1}\rfloor ⌊fn−1⌋最多有 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)。
#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;
}