题目大意
给你三个整数 n , d , l n,d,l n,d,l, n n n为正整数、负整数或0, d , l d,l d,l为正整数,你现在有一个数 k = 1 k=1 k=1,请你用以下三种操作,将 k k k的值变为 n n n
- 如果 min ( ∣ k ∣ , ∣ k − d ∣ ) ≤ l \min(|k|,|k-d|)\leq l min(∣k∣,∣k−d∣)≤l,将 k k k变为 k − d k-d k−d
- 将 k k k变为 2 k 2k 2k
- 如果 k ≡ 1 ( m o d 3 ) k\equiv 1\pmod3 k≡1(mod3),将 k k k变为 n − 1 3 \dfrac{n-1}{3} 3n−1
求将初始的 k k k(此时 k = 1 k=1 k=1)的值变为 n n n的操作方法,注意操作次数不能超过 1500 1500 1500。
题解
我们把构造的过程反过来,从 n n n到 1 1 1构造,那么操作 2 2 2和操作 3 3 3可以看做 n = n / 2 n=n/2 n=n/2和 n = 3 n + 1 n=3n+1 n=3n+1。可以想到角谷猜想。
如果 n n n为正整数,那么一定能让 n n n变为 1 1 1。
如果 n n n为负整数或0,则经过角谷猜想的操作,那么一定能使 n n n变为在 − 100 -100 −100到 0 0 0之间的整数。那么显然 ∣ n ∣ ≤ l |n|\leq l ∣n∣≤l,我们不断让 n n n变为 n + d n+d n+d,直到 n > 0 n>0 n>0,然后再用角谷猜想的操作让 n n n变为 1 1 1即可。
这样操作的次数并不会超过 1500 1500 1500次,实际上大部分都在 200 200 200到 300 300 300步左右。
code
#include<bits/stdc++.h>
using namespace std;
int q,d,l,n,re,ans[10005];
void dd(int i){
while(i!=1&&i!=0&&i!=-1&&i!=-5&&i!=-17){
if(i%2) i=i*3+1;
else i/=2;
ans[++ans[0]]=i;
}
re=i;
}
int main()
{
scanf("%d%d%d",&q,&d,&l);
while(q--){
ans[0]=0;
scanf("%d",&n);
if(n==0){
printf("1 1 0\n");
continue;
}
ans[++ans[0]]=n;
dd(n);
while(re<=0){
re+=d;
ans[++ans[0]]=re;
}
dd(re);
printf("%d ",ans[0]-1);
while(ans[0]){
printf("%d ",ans[ans[0]]);
--ans[0];
}
printf("\n");
}
return 0;
}