P10369 题解
跟官方有点不太一样的解法,可能会有些麻烦。
注意到最终剩下的数一定 ,所以构造的方案一定要使得最后剩下的数为 。
证明
设两个数 ()。
当 时,;
当 或 时,;
否则,。
综上 。
定义对长度为 的自然数序列 的一次分解操作,是将序列 替换为长度为 的序列 ,其中 ()。
最终的构造方案就是对 进行 次分解操作,最终得到的序列,答案肯定是不唯一的。
注意到长度为 的答案是可以由长度为 的答案分解得到。
尝试着分解,发现:
当 时,构造序列可以为 ;
当 时,由 分解得到 ;
当 时,由 分解得到 ;
当 时,由 分解得到 ;
当 时,由 分解得到 ;
当 时,由 分解得到 ;
以此类推,可以得到:
2
1 0
0 2 2
1 1 0 1
2 0 2 2 0
0 1 1 0 1 1
2 2 0 2 2 0 2
1 0 1 1 0 1 1 0
0 2 2 0 2 2 0 2 2
1 1 0 1 1 0 1 1 0 1
2 0 2 2 0 2 2 0 2 2 0
0 1 1 0 1 1 0 1 1 0 1 1
...
其中第 行表示当 等于 是 的答案。
把奇数行和偶数行分开来看。
2
0 2 2
2 0 2 2 0
2 2 0 2 2 0 2
0 2 2 0 2 2 0 2 2
2 0 2 2 0 2 2 0 2 2 0
1 0
1 1 0 1
0 1 1 0 1 1
1 0 1 1 0 1 1 0
1 1 0 1 1 0 1 1 0 1
0 1 1 0 1 1 0 1 1 0 1 1
发现第 行()的答案就是在第 行的答案头和尾各添加一个数。而第 行的序列为
发现奇数行添加的数为:
0 2
2 0
2 2
0 2
...
偶数行添加的数为:
1 1
0 1
1 0
1 1
...
由此就可以 构造了,具体实现见代码。
代码
#include<bits/stdc++.h>
using namespace std;
int t,n;
deque<int>q; //双端队列维护头和尾的添加
void Push(int x,int y){q.push_front(x),q.push_back(y);} //添加操作
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
while(!q.empty()) q.pop_back();
if(n&1){ //奇数行
q.push_back(2);
int s=n/2;
for(int i=1;i<=s;i++){
if(i%3==1) Push(0,2);
else if(i%3==2) Push(2,0);
else Push(2,2);
}
}
else{ //偶数行
Push(1,0);
int s=n/2-1;
for(int i=1;i<=s;i++){
if(i%3==1) Push(1,1);
else if(i%3==2) Push(0,1);
else Push(1,0);
}
}
while(!q.empty()){printf("%d ",q.front()),q.pop_front();}
putchar('\n');
}
return 0;
}

浙公网安备 33010602011771号