CF1453D题解
VP 的时候发现的一道数学题(
在思考这个问题之前,先让我们思考一件事:走到距离上一个存档点 \(n\) 的位置的期望是多少?(假设这个值为 \(f[n]\))
先思考 \(f[1]\) 是多少,很明显是:
\[S=\sum_{i=0}^{\infty}i \times 2^{-i} \]手拆一下:
\[2^{-1}S=\sum_{i=1}^{\infty}(i-1) \times 2^{-i} \]相减:
\[2^{-1}S=\sum_{i=1}^{\infty}2^{-i} \]很容易得到 \(2^{-1}S=1\),也就是 \(f[1]=2\) 当然你也可以通过观察样例来得到这个结论
来思考 \(f[n]\),考虑从 \(f[n-1]\) 递推过来。枚举失败的次数:
\[f[n]=\sum_{k=0}^{\infty}((k+1) \times f[n-1]+(k+1)) \times 2^{-k-1} \]\[f[n]=(f[n-1]+1)\sum_{k=1}^{\infty}k \times 2^{-k} \]于是有 \(f[n]=(f[n-1]+1) \times 2\)。手玩一下即可发现 \(f[n]=2^{n+2}-2\)。
因为期望具有线性性,(\(E(a+b)=E(a)+E(b)\))于是问题就变成了了如何用若干个 \(f\) 凑出 \(k\)。
变形一下,\(f[n]=2(2^{n+1}-1)\),说明 \(n\) 为奇数时一定不行。
于是我们枚举最大的 \(f\),枚举到一个就让 \(k\) 减去 \(f\),然后当做当前的 \(k\) 接着做。
#include
typedef long long ll;
ll k,f[61];int len,ans[2005];
signed main(){
int T,i,j;ll k;f[0]=2;scanf("%d",&T);
for(int i(1);i<=60;++i)f[i]=f[i-1]+1<<1;
while(T--){
scanf("%lld",&k);len=0;
if(k&1){
printf("-1\n");continue;
}
for(i=60;i>=0;--i){
while(k>=f[i]){
ans[++len]=1;
for(j=1;j<=i;++j)ans[++len]=0;k-=f[i];
}
}
printf("%d\n",len);
for(i=1;i<=len;++i)printf("%d ",ans[i]);printf("\n");
}
}