这题的构造技巧在于尽量简化操作,让贡献便于计算。
最简单的情况就是每一个数字只有两个了。
记一个长度为n的排列为,我们考虑构造这样一个序列(,1,2,...,n)。
容易发现,一个复读子序列要想出现在这里面,肯定是前一份在里面,后一份在(1,2,...,n)里面。
这就要求本身是一个递增序列。
因此这样一个序列的贡献实质就等于的上升子序列个数。
这样问题就简单了(虽然暂时我们也并不知道n取多大)。
考虑怎么构造一个凑出N的贡献。
由于存在以下递推式:
所以我们可以根据当前N的奇偶性,递归地解决子问题,从而构造出。
然后我们在末尾加上(1,2,...,n)就大功告成了。
显然不出两步N就会缩小一半,所以可以在步以内构造完毕。
由于N<=1e12,所以n<=80,|Q|<=160,长度足够短了。
#include <cstdio>
#include <vector>
#define ll long long
#define rep(i,j,k) for (i=j;i<=k;i++)
using namespace std;
ll n;
int i,k;
vector <int> a;
void solve(ll n,int &k)
{
if (n==1) {a.push_back(1); k=1; return ;}
if (n&1) {
solve((n-1)/2,k);
k++; a.push_back(k);
}
else {
solve(n-1,k);
k++; a.insert(a.begin(),k);
}
}
int main()
{
scanf("%lld",&n);
solve(n,k);
rep(i,1,k) a.push_back(i);
printf("%d\n",a.size());
rep(i,0,a.size()-1) printf("%d ",a[i]);
return 0;
}