题目链接:P8116 魔理沙的计算器
大意
给一个 b b b 进制的计算器,但屏幕上只能显示 k k k 位数字,求 b b b 进制下满足 1 ÷ ( 1 ÷ n ) = n 1\div(1\div n)=n 1÷(1÷n)=n 的 n n n 的个数,其中 1 ÷ n 1\div n 1÷n 和 1 ÷ ( 1 ÷ n ) 1\div(1\div n) 1÷(1÷n) 都使用计算器上显示的值。
题解
赛时就感觉这是个神仙思维题。
首先屏幕上只能显示有限位数字,也就说明如果 1 n \frac{1}{n} n1 是个无限小数是绝无可能满足 1 ÷ ( 1 ÷ n ) = n 1\div(1\div n)=n 1÷(1÷n)=n 的。
这个地方我们形式化描述一下,如果 1 n \frac{1}{n} n1 是个无限小数,设屏幕上显示的 1 ÷ n 1\div n 1÷n 为 n ′ = 0. a 1 a 2 ⋯ a k − 1 n'=0.a_1a_2\cdots a_{k-1} n′=0.a1a2⋯ak−1,那么因为小数点后第 k k k 位及之后被省去, n ′ n' n′ 再乘上 n n n 得到的结果相比 1 1 1 一定会在小数点后第 k − 1 k-1 k−1 位有缺失。
那么如果在屏幕上显示 1 ÷ n ′ = n 1\div n'=n 1÷n′=n 就会出现矛盾。屏幕上显示 n n n 说明 1 ÷ n ′ 1\div n' 1÷n′ 的结果 n ′ ′ n'' n′′ 至少在小数点后第 k − 1 k-1 k−1 位及之前都为 0 0 0,而 n ′ n' n′ 小于零, n ′ ′ n'' n′′ 小数点后第 k k k 位及以后乘上 n ′ n' n′ 的贡献显然无法弥补小数点后第 k − 1 k-1 k−1 位的缺失。所以上面的结论成立。
举个栗子,假如拿十进制下的 1 ÷ 7 1\div 7 1÷7 在屏幕上得到 0.1428 0.1428 0.1428,会有 0.1428 × 7 = 0.9996 0.1428\times 7=0.9996 0.1428×7=0.9996,在小数点后第 4 4 4 位上就出现了缺失。那么我拿 1 ÷ 0.1428 1\div 0.1428 1÷0.1428 就不可能在屏幕上显示 7 7 7(即除出来的真正结果为 7.0000 ⋯ 7.0000\cdots 7.0000⋯),因为这样的话那 0.0004 0.0004 0.0004 的差距不会被弥补。
(这个地方可能说的有点绕,但理是这么个理。)
那么范围就缩小到所有 b b b 进制下除 1 1 1 能得到有限小数的数。然而又有 k k k 位的限制,这就要求 1 n \frac{1}{n} n1 的小数点后数字位数不能大于 k − 1 k-1 k−1 位(因为整数部分也占一位)。
设 1 ÷ n 1\div n 1÷n 的真实值为 0. c 1 c 2 ⋯ c k − 1 0.c_1c_2\cdots c_{k-1} 0.c1c2⋯ck−1,小数部分不足 k − 1 k-1 k−1 位的用零补齐。自然想到将 1 1 1 和 0. c 1 c 2 ⋯ c k − 1 0.c_1c_2\cdots c_{k-1} 0.c1c2⋯ck−1 同乘 b k − 1 b^{k-1} bk−1,得到 b b b 进制下的 100 ⋯ 0 100\cdots0 100⋯0 和 c 1 c 2 ⋯ c k − 1 ‾ \overline{c_1c_2\cdots c_{k-1}} c1c2⋯ck−1。
又由题, b b b 进制下的 c 1 c 2 ⋯ c k − 1 ‾ \overline{c_1c_2\cdots c_{k-1}} c1c2⋯ck−1 必然是 100 ⋯ 0 100\cdots0 100⋯0 的一个因子,我们要求的 n n n 的个数实际上就是满足要求的 c 1 c 2 ⋯ c k − 1 ‾ \overline{c_1c_2\cdots c_{k-1}} c1c2⋯ck−1 的个数,也即 100 ⋯ 0 [ b ] 100\cdots0_{[b]} 100⋯0[b] 的因子个数。所以将 100 ⋯ 0 [ b ] 100\cdots0_{[b]} 100⋯0[b] 转回十进制得到 b k − 1 b^{k-1} bk−1,问题转化为求 b k − 1 b^{k-1} bk−1 的因子个数。
这下这个题目就很数学了,直接对 b b b 分解质因数,根据唯一分解定理的推论求因子个数即可。
代码
#include<bits/stdc++.h>
using namespace std;
#define N 100003
#define LL long long
#define INF 0x3f3f3f3f
#define MOD 998244353
int t,b,k;
LL h[N];
int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d",&b,&k);
LL ans=1;
int a=b,ct=0;
for(int i=2;i*i<=b;++i)
if(a%i==0){
ct++;
while(a%i==0) a/=i,h[ct]++;
h[ct]=h[ct]*(k-1)%MOD;
}
if(a>1) h[++ct]=k-1;
for(int i=1;i<=ct;++i)
ans=ans*(h[i]+1)%MOD,h[i]=0;
printf("%lld\n",ans);
}
return 0;
}