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");
	}
}