题解 CF1864C Divisor Chain
题意
给定一个整数 $x\ (2 \le x \le 10^9)$,你每次可以选择一个 $d \mid x$,并将 $x=x-d$。
你需要做这样的操作至多 $1000$ 次,并且不能使用同一个 $d$ 超过 $2$ 次。
求解将 $x$ 变为 $1$ 的操作序列。
分析
赛时找了很久规律,才发现是二进制拆分。
对 $x$ 进行二进制拆分,设 $x=\sum\limits_{i=1}^m2^{b_i}$, 满足 $\forall i \in [1,m) ,b_i>b_{i+1} \ge 0$。
观察可以发现:$$ \begin{matrix} \because a_1=x=\sum\limits_{i=1}^m2^{b_i}=2^{b_m}\sum\limits_{i=1}^m2^{b_i-b_m}\\ \therefore 2^{b_m} \mid a_1\\ \because a_2=a_1-2^{b_m}=\sum\limits_{i=1}^{m-1}2^{b_i}=2^{b_{m-1}}\sum\limits_{i=1}^{m-1}2^{b_i-b_{m-1}}\\ \therefore 2^{b_{m-1}} \mid a_2\\ \cdots\\ \therefore 2^{b_1} \mid a_m \end{matrix} $$ 所以可以证明:$$ \forall i\in[1,m],2^{b_{m-i+1}}\mid a_i $$ 所以我们可以从小到大依次减去 $2$ 的最低次幂,直到仅剩 $2$ 的最高次幂。
接着将 $2$ 的最高次幂依次砍半即可,易证每个减数不会使用超过 $2$ 次。
代码
//the code is from chenjh
#include<cstdio>
#include<algorithm>
#include<vector>
void solve(){
int x;scanf("%d",&x);
std::vector<int> v;//操作序列。
v.emplace_back(x);
int y=1<<std::__lg(x);//求 x 的 2 的最高次幂。
int z=x-y;
for(int i=0;i<=30;i++)if(z&(1<<i))v.emplace_back(x-=(1<<i));//从小到大减去这一位。
while(y>1)v.emplace_back(y>>=1);//每次砍半。
printf("%zu\n",v.size());
for(const int y:v) printf("%d ",y);
putchar('\n');
}
int main(){
int T;scanf("%d",&T);
while(T--) solve();
return 0;
}

浙公网安备 33010602011771号