描述
题解
这个题用到了蒙哥马利约化的知识,并且在这种高精度模幂时,我们只需要考虑剩余类环中的情况,大于这个的高位可以直接忽略掉,因为肯定可以被模消除,据说还用到了鸽舍原理,我也不是特别能理解这个题,官方题解有些不走心,公式难道是代码解析出问题了?怎么感觉残缺啊~~~
这个代码的核心部分是 tmp 循环判断这部分, tmp 表示对应的每一位,从低位开始,逐个去配凑,一直到配出 tmp 等于 A <script type="math/tex" id="MathJax-Element-337">A</script> 对应位的值,此时,配凑的关键是建立在之前低位的周期上,所以经过数次迭代,低位依然是不再改变的,无论怎么迭代,都能返回到初始的状态,所以,用一句话来说,就是逐位周期性递推即可,一直到推完 K 位,最后则是 所有位数迭代次数的连乘 + 1
,为最终结果。
没毛病,理解起来实在是有些困难,得好一段时间静下心来细细分析代码~~~
代码
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int CUT = 1e9;
const int MAXN = 666;
const int MAX_POW_10 = 10;
const int BASE_B = MAX_POW_10;
const int MAGIC = 9;
const int MAX_ANS = 5e3;
const int MAX_ = 100;
int k, flag = -1;
char n[MAXN];
int C[MAXN];
int ans[MAX_ANS];
ll A[MAX_];
ll B[MAX_];
ll T[MAX_];
ll Nx1[MAX_];
ll Nx2[MAX_];
ll POW_10[MAX_POW_10] = {
1};
void init()
{
for (int i = 1; i < MAX_POW_10; i++)
{
POW_10[i] = POW_10[i - 1] * BASE_B;
}
}
void read()
{
scanf("%s%d", n, &k);
int len = (int)strlen(n);
int cnt = 0;
for (int i = len - 1; i > -1; i -= MAGIC, cnt++)
{
int sz = max(-1, i - MAGIC);
for (int j = i, t = 0; j > sz; j--, t++)
{
A[cnt] += POW_10[t] * (ll)(n[j] - '0');
}
}
}
void mul(ll res[], ll scr[])
{
memset(T, 0, sizeof(T));
for (int i = 0; i < k; i++)
{
ll c = 0;
for (int j = 0; j + i < k; j++)
{
T[i + j] += Nx1[i] * scr[j] + c;
c = T[i + j] / CUT;
T[i + j] -= c * CUT;
}
}
memcpy(res, T, sizeof(T));
}
void solve()
{
int K = k;
k = k / MAGIC + 1;
memcpy(B, A, sizeof(A));
memcpy(Nx2, A, sizeof(A));
Nx1[0] = 1;
for (int i = 0; i < K; i++)
{
memcpy(A, B, sizeof(B));
int dx = i / MAGIC;
int dd = i % MAGIC;
ll tmp = (B[dx] / POW_10[dd]) % BASE_B; // 对应第 i 位的值
do
{
mul(Nx1, Nx2);
mul(A, B);
ans[i]++;
}
while (tmp != ((A[dx] / POW_10[dd]) % BASE_B) && ans[i] < 12);
if (ans[i] > 11)
{
return ;
}
memcpy(Nx2, Nx1, sizeof(Nx1));
memset(Nx1, 0, sizeof(Nx1));
Nx1[0] = 1;
}
C[0] = 1;
int deep = 1;
for (int i = 0; i < K; i++)
{
int j = 0, c = 0;
for (; j < deep; j++)
{
C[j] *= ans[i];
C[j] += c;
c = C[j] / 10000;
C[j] -= c * 10000;
}
if (c > 0)
{
C[deep++] = c;
}
}
C[0]++;
int i = 0, c = 0;
for (; i < deep; i++)
{
C[i] += c;
c = C[i] / 10000;
C[i] -= c * 10000;
if (c == 0)
{
break;
}
}
if (c > 0)
{
C[deep++] = c;
}
deep--;
flag = deep;
}
void print()
{
if (flag != -1)
{
printf("%d", C[flag--]);
while (flag > -1)
{
printf("%04d", C[flag--]);
}
printf("\n");
}
else
{
printf("1\n");
}
}
int main ()
{
init();
read();
solve();
print();
return 0;
}