题目
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{egin{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} ight.),消元得到(f(1)=f(3)+6),易知对于任意位置的这种串,该关系依然成立,所以之后我们就以第(1)关作为开头。
假设第(1)关为(1),第(2,3)关为(0),有方程组(left{egin{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} ight.),解得(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<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
");
continue;
}
if(k==2){
printf("1
1
");
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
",cnt);
for(i=1;i<=cnt;i++)
printf("%d ",ans[i]);
printf("
");
}
return 0;
}