P1532 卡布列克圆舞曲
网页链接
题目描述
卡布列克是一位数学家,他在研究数字时发现:任意一个不是用完全相同数字组成的四位数,如果对它们的每位数字重新排序,组成一个较大的数和一个较小的数,然后用较大数减去较小数,差不够四位数时补零,类推下去,最后将变成一个固定的数:,这就是卡布列克常数,例如:
。
。
。
。
如果 位数也照此办理,它们不是变成一个数,而是在几个数字之间形成循环,称作卡布列克圆舞曲。例如对于五位数 :
。
。
。
。
。
。
我们把 称作循环节,即卡布列克圆舞曲。
输入格式
若干行,每行为一个待求“卡布列克圆舞曲”的起始整数 。()
输出格式
每行为对应整数的循环节,数据之间用空格隔开。
输入输出样例 #1
输入 #1
4321
54321
输出 #1
6174
82962 75933 63954 61974
解题思路
本题是数字黑洞(卡布列克常数)的模拟与循环检测问题,通过对整数反复进行“重排最大数减最小数”的操作,记录过程中出现的所有数值,一旦遇到重复即定位循环节并输出。
1. 问题等价转化
- 卡布列克操作:对于整数 ,将其各位数字取出,分别按升序和降序排列,组成最小数 和最大数 ,计算 。若结果位数不足原数位数,在运算过程中自然由数字前导零的忽略而实现“补零”效果(例如 排序后最小数视为 ,最大数 )。
- 循环节定义:从某个起点开始,反复执行上述操作,最终会进入一个循环。循环节即从第一次出现的某个数开始,到再次出现该数之前的所有数构成的序列。
- 目标:对于每个输入整数 ,输出其进入的循环节(数据之间用空格隔开)。
2. 算法实现
- 输入与初始化:循环读取整数 (直至 EOF)。对于每个 :
- 清空记录数组
a,下标ind置 0。 - 将初始值 存入
a[++ind]。
- 清空记录数组
- 迭代操作:
- 设置标志
flag = true,进入循环。 - 提取 的各位数字存入数组
b,记录位数cnt。 - 对
b[1..cnt]排序。 - 构造最小数
n1:从b[1]到b[cnt]依次拼成十进制数。 - 构造最大数
n2:从b[cnt]到b[1]依次拼成十进制数。 - 计算新数
n = n2 - n1。 - 遍历已记录的数组
a,检查 是否已出现过。若已出现(a[i] == n),则循环节为a[i]到a[ind]的所有元素,输出后设置flag = false结束循环。 - 否则将 追加到
a[++ind]中继续迭代。
- 设置标志
- 输出格式:每找到一组循环节,按顺序输出数字,空格分隔,最后换行。
3. 复杂度分析
- 时间复杂度:每次操作需要 排序数字( 为位数,最多 位),迭代步数受限于整数范围和循环长度,远小于 级别,每轮极快。
- 空间复杂度: 存储过程值, 为循环前序列长度,规模很小。
总结
通过反复执行“重排相减”操作,并将每次结果记录下来,借助线性查找检测重复,精确提取出卡布列克圆舞曲的循环节。由于操作对象不超过 ,循环长度有限,模拟完全可行。
代码简要说明
-
全局变量与数组
a[100000]:记录操作过程中依次产生的数。ind:当前记录数量指针。
-
主循环
while(cin >> n)处理多组数据。- 初始化
ind=0,将 存入a[++ind]。 flag=true控制迭代,直到发现循环。- 提取数字位到
b,排序后用n1(升序)、n2(降序)做差。 - 遍历已存数组
a,若a[i] == n则输出从i到ind的所有数,置flag=false。 - 否则将新数继续记录。
-
输出:每行结束后输出换行。
代码内容
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
typedef vector<vector<ll>> vvt;
typedef pair<ll,ll> pll;
const ll N=1e3+10;
const ll INF=1e18;
const ll M=1e6+10;
const ll mod=1e9+7;
ll ind;
ll a[100000], n;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
while(cin >> n)
{
ind = 0;
a[++ind] = n;
bool flag = true;
while(flag)
{
ll b[20] = {0}, n1 = 0, n2 = 0;
ll cnt = 0;
while(n)
{
b[++cnt] = n % 10;
n /= 10;
}
sort(b + 1, b + 1 + cnt);
for(ll i = 1; i <= cnt; i++) n1 = n1 * 10 + b[i];
for(ll i = cnt; i >= 1; i--) n2 = n2 * 10 + b[i];
n = n2 - n1;
for(ll i = 1; flag && i <= ind; i++)
if(a[i] == n)
{
flag = false;
for(ll j = i; j <= ind; j++) cout << a[j] << " ";
}
a[++ind] = n;
}
cout << endl;
}
return 0;
}