90 lines
3.6 KiB
C++
90 lines
3.6 KiB
C++
|
|
#include <bits/stdc++.h>
|
|||
|
|
using namespace std;
|
|||
|
|
|
|||
|
|
// 常量定义:数组最大长度为110,满足k≤100的需求
|
|||
|
|
const int N = 110;
|
|||
|
|
|
|||
|
|
// 全局变量声明
|
|||
|
|
int k; // 存储用户输入的k值,表示需要计算后k位的循环节长度
|
|||
|
|
int a[N]; // 存储原始整数n的后k位数字(倒序存储:a[0]为个位,a[1]为十位...)
|
|||
|
|
int b[N]; // 工作数组,用于存储幂运算的中间结果
|
|||
|
|
int d[N] = {1}; // 高精度数组,存储最终循环节长度(初始值为1,乘法单位元)
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 高精度乘法函数:计算两个数的乘积并仅保留后K位
|
|||
|
|
* @param a 乘数1(倒序存储的高精度数组)
|
|||
|
|
* @param b 乘数2(倒序存储的高精度数组)
|
|||
|
|
* @note 结果将直接覆盖存储在a数组中
|
|||
|
|
*/
|
|||
|
|
void mul(int a[], int b[]) {
|
|||
|
|
int c[N] = {0}; // 临时数组,存储乘法中间结果
|
|||
|
|
|
|||
|
|
// 1. 执行乘法运算(仅计算后K位)
|
|||
|
|
for (int i = 0; i < k; i++)
|
|||
|
|
for (int j = 0; j < k; j++)
|
|||
|
|
if (i + j < k) // 确保不超出K位范围
|
|||
|
|
c[i + j] += a[i] * b[j];
|
|||
|
|
|
|||
|
|
// 2. 处理进位并更新结果到a数组
|
|||
|
|
int t = 0; // 进位变量
|
|||
|
|
for (int i = 0; i < k; i++) {
|
|||
|
|
t += c[i]; // 累加当前位乘积和进位
|
|||
|
|
a[i] = t % 10; // 取模10得到当前位值
|
|||
|
|
t /= 10; // 更新进位
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int main() {
|
|||
|
|
string s; // 存储输入的超大整数n(支持10^100量级)
|
|||
|
|
cin >> s >> k; // 读取输入:n和k
|
|||
|
|
|
|||
|
|
// 1. 初始化原始数组a(倒序存储n的后K位)
|
|||
|
|
for (int i = s.size() - 1; i >= 0; i--)
|
|||
|
|
a[s.size() - 1 - i] = s[i] - '0';
|
|||
|
|
|
|||
|
|
// 2. 逐位计算循环节(从最后1位到第k位)
|
|||
|
|
for (int i = 0; i < k; i++) {
|
|||
|
|
int st[11] = {0}; // 数字出现标记数组(检测循环冲突)
|
|||
|
|
memcpy(b, a, sizeof a); // 复制初始状态到工作数组b
|
|||
|
|
|
|||
|
|
int j; // 当前位的循环节长度
|
|||
|
|
// 最多尝试10次(0-9共10个可能数字,超过则无循环)
|
|||
|
|
for (j = 1; j <= 10; j++) {
|
|||
|
|
mul(b, a); // 计算b = b * a(仅保留后K位)
|
|||
|
|
|
|||
|
|
// 检查当前位是否回到初始值(找到循环节)
|
|||
|
|
if (b[i] == a[i]) break;
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
### 举例说明:
|
|||
|
|
假设计算过程中出现数字序列: 3 → 7 → 2 → 7
|
|||
|
|
- 当第二次出现7时,由于尚未回到初始值3,触发此冲突检测
|
|||
|
|
- 这表明序列陷入了局部循环(7→2→7),永远无法回到初始值
|
|||
|
|
这个机制确保了算法能够正确识别无法形成有效循环节的情况,是解决问题的关键判断条件之一。
|
|||
|
|
*/
|
|||
|
|
// 检测到数字重复出现但未回到初始值(存在循环冲突,无解决方案)
|
|||
|
|
if (st[b[i]]) {
|
|||
|
|
puts("-1");
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
st[b[i]] = 1; // 标记该数字已出现
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 3. 更新循环节长度(高精度乘法:d = d * j)
|
|||
|
|
int c[N] = {j}; // 将j转换为高精度数组
|
|||
|
|
mul(d, c); // 累乘当前位的循环节长度
|
|||
|
|
|
|||
|
|
// 4. 更新乘数a为n^j的后K位(固定已计算的低位循环)
|
|||
|
|
memcpy(b, a, sizeof a); // 重置b为初始值
|
|||
|
|
for (int q = 1; q < j; q++)
|
|||
|
|
mul(b, a); // 计算a^j的后K位
|
|||
|
|
memcpy(a, b, sizeof b); // 更新a为新的乘数
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 4. 输出结果(去除前导零)
|
|||
|
|
int dl = k - 1;
|
|||
|
|
while (dl >= 0 && d[dl] == 0) dl--; // 找到最高有效位
|
|||
|
|
for (int i = dl; i >= 0; i--)
|
|||
|
|
cout << d[i];
|
|||
|
|
return 0;
|
|||
|
|
}
|