題意
構造一串長 n n n的零一序列 ( n < = 2000 ) (n<=2000) (n<=2000)
有 1 2 \frac{1}{2} 21的概率成功通過第 i i i個關卡
如果失敗,立刻返回小於等於 i i i的最小的 1 1 1位置
觀察發現如果單獨一個 1 1 1,穿過去的期望步數是 2 2 2
如果要算也很簡單,設穿過一個單獨的 1 1 1的期望是 x x x
有 1 2 \frac{1}{2} 21的概率一步穿過, 1 2 \frac{1}{2} 21的概率一步失敗,還需要期望 x x x通過
那麼 x = 1 2 ∗ 1 + 1 2 ∗ ( x + 1 ) x=\frac{1}{2}*1+\frac{1}{2}*(x+1) x=21∗1+21∗(x+1)
解得 x = 2 x=2 x=2
那麼最後構造的序列就可以分解爲若干個形如1 0 0 0的形式(當然 1 1 1後面也可以沒有 0 0 0)
定義 f [ i ] f[i] f[i]爲開頭一個 1 1 1,後面跟 i − 1 i-1 i−1個 0 0 0的期望通過步數
那麼由上面的推導得 f [ 1 ] = 2 f[1]=2 f[1]=2
可以得到以下遞推式
f [ i ] = f [ i − 1 ] + 1 + 1 2 ∗ [ f [ i − 1 ] + ( f [ i ] − f [ i − 1 ] ) ] f[i]=f[i-1]+1+\frac{1}{2}*[f[i-1]+(f[i]-f[i-1])] f[i]=f[i−1]+1+21∗[f[i−1]+(f[i]−f[i−1])]
我解釋下這個方程,想突破第 i i i個關卡,前提是突破前 i − 1 i-1 i−1個關卡,期望是 f [ i − 1 ] f[i-1] f[i−1]
現在用一次機會嘗試突破第 i i i個關卡,期望是 1 1 1
1 2 \frac{1}{2} 21的概率突破了第 i i i個關卡,不需要加額外的花費
1 2 \frac{1}{2} 21的概率沒有突破回到一開始的位置 1 1 1
那麼首先需要回到第 i − 1 i-1 i−1個位置需要 f [ i − 1 ] f[i-1] f[i−1],突破第 i i i個關卡需要期望 f [ i ] − f [ i − 1 ] f[i]-f[i-1] f[i]−f[i−1]
所以得到上面的式子,把右邊的 f [ i ] f[i] f[i]移項到左邊,解得 f [ i ] f[i] f[i]
f [ i ] = 2 ∗ f [ i − 1 ] + 2 f[i]=2*f[i-1]+2 f[i]=2∗f[i−1]+2
所以發現每一個小單元都是偶數期望,所以當 k k k爲奇數無解
否則一定是從大到小構造 1 0 0 0 0... 1\ 0\ 0\ 0\ 0... 1 0 0 0 0...
因爲最後的組成單元是 f [ 1 ] = 2 f[1]=2 f[1]=2,所以只要是偶數的 k k k,都可以構造出來
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=3e5+10;
int f[maxn],k;
vector<int>ans;
signed main()
{
f[1] = 2;
for(int i=2;i<=60;i++) f[i] = 2*f[i-1]+2;
int t; cin >> t;
while( t-- )
{
ans.clear(); int flag = 1;
cin >> k;
while( k )
{
for(int i=60;i>=1;i--)
if( f[i]<=k )
{
k-=f[i]; ans.push_back(1);
for(int j=2;j<=i;j++) ans.push_back(0);
break;
}
if( k%2==1 ){
flag=0; break; }
}
if( ans.size()>2000 ) flag=0;
if( flag == 0 ) cout << -1;
else
{
cout << ans.size() << endl;
for(int i=0;i<ans.size();i++)
cout << ans[i] << " ";
}
cout << endl;
}
}