codeforces 1453D Checkpoints
题目
http://codeforces.com/problemset/problem/1453/D
1453?精罗震怒!
题意
这是一个闯关游戏,一些关卡有标记,一些没有(规定1号节点是有标记的)。玩家按顺序闯关,如果在第\(i\)关挑战成功,进入第\(i+1\)关;如果失败,返回关卡\(1-i\)中最靠后的有标记的关卡\(j\)。
返回之后,\(j\)及\(j\)之后的关卡需要重新挑战,成功和失败的结果同上面一样。通过最后一关后,游戏结束。
玩家在每一关的成功概率都为\(\frac{1}{2}\),现给定一个k,让你构造一组关卡(0表示无标记,1表示有标记),使得玩家的期望挑战次数正好为k。
思路
这是一道构造题。
先设一个函数\(f(x)\),表示进入了第\(x\)关后期望挑战次数。
假设共有\(n\)关(\(n\)未知),钦定第\(n\)关为1,那么有\(f(n)=2\)
假设第\(i\)关为\(1\),那么\(f(i)=\frac{1}{2}f(i)+\frac{1}{2}f(i+1)+1\),移项整理得\(f(i)=f(i+1)+2\),也就是说,每一个1,对答案的贡献为2。(小数据就这么水过去了)。
假设第\(1\)关为\(1\),而第\(2\)关为\(0\),那么有方程组\(\left\{\begin{array}\\f(2)=\frac{1}{2}f(3)+\frac{1}{2}f(1)+1\\f(1)=\frac{1}{2}f(2)+\frac{1}{2}f(1)+1 \end{array}\right.\),消元得到\(f(1)=f(3)+6\),易知对于任意位置的这种串,该关系依然成立,所以之后我们就以第\(1\)关作为开头。
假设第\(1\)关为\(1\),第\(2,3\)关为\(0\),有方程组\(\left\{\begin{array}\\f(3)=\frac{1}{2}f(4)+\frac{1}{2}f(1)+1\\f(2)=\frac{1}{2}f(3)+\frac{1}{2}f(1)+1\\f(1)=\frac{1}{2}f(2)+\frac{1}{2}f(1)+1 \end{array}\right.\),解得\(f(1)=f(4)+14\)。
观察一下:
\(2\)
\(6=2+4\)
\(14=2+4+8\)
大胆猜想,连续\(i\)个\(0\)对答案的贡献为\(2+4+...+2^{i+1}\)(可能数学归纳法可以证?但是我太懒▽),最终的序列可以表示为 1 00...1 00...1.... 这种形式
大体思路就是这样,有一些细节或者边界条件处理一下就好(还是比较烦的)。
代码
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define ll long long
using namespace std;
int ans[2001],cnt=0;
ll d[100];
int main(){
int i,j,n,m,t;
ll k;
scanf("%d",&t);
d[0]=2;
for(i=1;i<=60;i++)
d[i]=d[i-1]+(1ll<<i+1);
while(t--){
scanf("%lld",&k);
if(k&1){
printf("-1\n");
continue;
}
if(k==2){
printf("1\n1\n");
continue;
}
ll n=k-2;
cnt=1;
ans[1]=1;
while(n>0){
i=0;
while(d[i]<=n&&i<=60){
i++;
}
i--;
for(j=1;j<=i;j++)
ans[++cnt]=0;
n-=d[i];
ans[++cnt]=1;
}
printf("%d\n",cnt);
for(i=1;i<=cnt;i++)
printf("%d ",ans[i]);
printf("\n");
}
return 0;
}