D.Big Intege
题意
已知
A
(
n
)
=
11111
⋯
11111
A(n)=11111\cdots11111
A(n)=11111⋯11111(n为1的数量)
求
A
(
i
j
)
m
o
d
  
p
=
0
A(i^j) \mod p=0
A(ij)modp=0的数量
(
1
≤
i
≤
n
,
1
≤
j
≤
m
)
(1\leq i \leq n,1\leq j \leq m)
(1≤i≤n,1≤j≤m)
思路
公式推导
第一步
令
n
=
i
j
n=i^j
n=ij
显然,
11111
⋯
11111
11111\cdots11111
11111⋯11111是个很优美的数字
A
(
n
)
=
1
0
n
−
1
9
A(n)=\frac{10^n-1}{9}
A(n)=910n−1
第二步
1
0
n
−
1
9
%
p
=
=
0
\frac{10^n-1}{9} \% p==0
910n−1%p==0
除了
p
=
=
3
p==3
p==3,
p
p
p和
9
9
9都是互质的,那么
- 1 0 n − 1 9 % p \frac{10^n-1}{9} \% p 910n−1%p
- = ( 1 0 n − 1 ) ∗ i n v 9 % p =(10^n-1)*inv9\% p =(10n−1)∗inv9%p
- = ( ( 1 0 n − 1 ) % p ) ∗ ( i n v 9 % p ) % p =((10^n-1)\% p)*(inv9 \% p) \%p =((10n−1)%p)∗(inv9%p)%p
- = 0 =0 =0
第三步
因为互质
i
n
v
9
≠
0
inv9 \neq 0
inv9̸=0
(
(
1
0
n
−
1
)
%
p
)
∗
(
i
n
v
9
%
p
)
%
p
((10^n-1)\% p)*(inv9 \% p) \%p
((10n−1)%p)∗(inv9%p)%p
所以推出
1
0
n
−
1
%
p
=
=
0
10^n-1 \% p==0
10n−1%p==0
1
0
n
≡
1
m
o
d
  
p
10^n\equiv 1\mod p
10n≡1modp
第四步
用以下随便哪个定理都一样
费马小定理:
**若
a
a
a不是
p
p
p的倍数,
a
p
−
1
≡
1
m
o
d
  
n
a^{p-1} \equiv 1 \mod n
ap−1≡1modn **
显然
p
−
1
p-1
p−1属于
n
n
n,但
p
−
1
p-1
p−1不一定最小的满足的数
若存在
d
(
d
≤
p
−
1
)
d(d \leq p-1)
d(d≤p−1)满足上式,
d
d
d一定是
p
−
1
p-1
p−1的约数(同余式的性质)
欧拉定理引理:
若
a
,
n
a,n
a,n互质,则满足
a
x
≡
1
m
o
d
  
n
a^x\equiv 1 \mod n
ax≡1modn的最小正整数
x
x
x是
Θ
(
n
)
\Theta(n)
Θ(n)的约数
如此枚举约数即可求出最小的x满足 1 0 x ≡ m o d    1 10^x \equiv \mod 1 10x≡mod1
int big_d[32000];
LL Get_Min_d(LL p) {
LL phi = p - 1; int k = 0;
for (int i = 1; i * i <= phi; i++) {
if (phi % i == 0) {
if (quickpow(10, i, p) == 1) //快速幂
return i;
big_d[++k] = phi / i; //大的因数先存起来
}
}
for (int i = k; i >= 1; i--) { //小的因数找不到,再找大的
if (quickpow(10, big_d[i], p) == 1)
return big_d[i];
}
}
第五步
显然满足
1
0
d
m
o
d
  
p
=
=
1
10^d \mod p==1
10dmodp==1的最小循环节d只有一个
证明:
若存在
d
1
,
d
2
d_{1},d_{2}
d1,d2且
d
1
d_{1}
d1和
d
2
d_{2}
d2互质
1
0
d
1
m
o
d
  
p
=
=
1
10^{d_{1}} \mod p==1
10d1modp==1
1
0
d
2
m
o
d
  
p
=
=
1
10^{d_{2} }\mod p==1
10d2modp==1
那么必定存在
1
0
(
d
2
−
d
1
)
m
o
d
  
p
=
=
1
10^{(d_{2}-d_{1})} \mod p==1
10(d2−d1)modp==1,依次类推做辗转相减法
存在
d
=
g
c
d
(
d
1
,
d
2
)
d=gcd(d_{1},d_{2})
d=gcd(d1,d2),那么d就是唯一循环节
问题转化
若我们找到最小循环节d,那么所有满足 1 0 d m o d    p = = 1 10^d \mod p==1 10dmodp==1,那么只要找到所有 i j i^j ij中的倍数即可
i j i^j ij中d的倍数
ps:此处公式中 [ x ] [x] [x]为将x向上取整
第一步
将d分解质因数, d = p 1 a 1 ∗ p 2 a 2 ∗ p 3 a 3 ∗ ⋯ ∗ p n a n d=p_{1}^{a_{1}}*p_{2}^{a_{2}}*p_{3}^{a_{3}}*\cdots*p_{n}^{a_{n}} d=p1a1∗p2a2∗p3a3∗⋯∗pnan
第二步
若确定
j
j
j,则
i
i
i一定是min_d的倍数
m
i
n
(
d
)
=
p
1
[
a
1
j
]
∗
p
2
[
a
2
j
]
∗
p
3
[
a
3
j
]
∗
⋯
∗
p
n
[
a
n
j
]
min(d)=p_{1}^{[\frac{a_{1}}{j}]}*p_{2}^{[\frac{a_{2}}{j}]}*p_{3}^{[\frac{a_{3}}{j}]}*\cdots*p_{n}^{[\frac{a_{n}}{j}]}
min(d)=p1[ja1]∗p2[ja2]∗p3[ja3]∗⋯∗pn[jan]
因为
m
i
n
(
d
)
j
=
p
1
[
a
1
j
]
∗
j
∗
p
2
[
a
2
j
]
∗
j
∗
p
3
[
a
3
j
]
∗
j
∗
⋯
∗
p
n
[
a
n
j
]
∗
j
min(d)^j=p_{1}^{[\frac{a_{1}}{j}]*j}*p_{2}^{[\frac{a_{2}}{j}]*j}*p_{3}^{[\frac{a_{3}}{j}]*j}*\cdots*p_{n}^{[\frac{a_{n}}{j}]*j}
min(d)j=p1[ja1]∗j∗p2[ja2]∗j∗p3[ja3]∗j∗⋯∗pn[jan]∗j
=
d
∗
p
1
[
a
1
j
]
∗
j
−
a
1
∗
p
2
[
a
2
j
]
∗
j
−
a
2
∗
p
3
[
a
3
j
]
∗
j
−
a
3
∗
⋯
∗
p
n
[
a
n
j
]
∗
j
−
a
n
=d*p_{1}^{[\frac{a_{1}}{j}]*j-a_{1}}*p_{2}^{[\frac{a_{2}}{j}]*j-a_{2}}*p_{3}^{[\frac{a_{3}}{j}]*j-a_{3}}*\cdots*p_{n}^{[\frac{a_{n}}{j}]*j-a_{n}}
=d∗p1[ja1]∗j−a1∗p2[ja2]∗j−a2∗p3[ja3]∗j−a3∗⋯∗pn[jan]∗j−an
例如:对于
12
=
2
2
∗
3
1
12=2^2*3^1
12=22∗31
当
j
=
1
j=1
j=1,
m
i
n
(
d
)
=
2
2
∗
3
1
=
12
min(d)=2^2*3^1=12
min(d)=22∗31=12,
12
12
12的倍数的
1
1
1次方,为
12
12
12的倍数
当
j
=
2
j=2
j=2,
m
i
n
(
d
)
=
2
1
∗
3
1
=
6
min(d)=2^1*3^1=6
min(d)=21∗31=6,
6
6
6的倍数的
2
2
2次方,为
12
12
12的倍数
当
j
=
3
j=3
j=3,
m
i
n
(
d
)
=
2
1
∗
3
1
=
6
min(d)=2^1*3^1=6
min(d)=21∗31=6,
6
6
6的倍数的
3
3
3次方,为
12
12
12的倍数
第三步
显然
1
−
n
1-n
1−n中min_d的倍数个数为
n
/
m
i
n
(
d
)
n/min(d)
n/min(d)
对于
1
≤
j
≤
m
a
x
(
a
1
,
a
2
,
⋯
 
,
a
n
)
1\leq j\leq max(a_{1},a_{2},\cdots,a_{n})
1≤j≤max(a1,a2,⋯,an),
m
i
n
(
d
)
min(d)
min(d)是不同的
对于
m
a
x
(
a
1
,
a
2
,
⋯
 
,
a
n
)
<
j
max(a_{1},a_{2},\cdots,a_{n})< j
max(a1,a2,⋯,an)<j,
m
i
n
(
d
)
=
p
1
∗
p
2
∗
p
3
∗
⋯
∗
p
n
min(d)=p_{1}*p_{2}*p_{3}*\cdots*p_{n}
min(d)=p1∗p2∗p3∗⋯∗pn
先分解质因数
再枚举
j
j
j计算,min_d的倍数个数
分解质因数
int p[32], a[32], cnt; //p数组为质因数,a数组为次数
void Dec(LL d) {
fill(p, p + 32, 0);
fill(a, a + 32, 0); cnt = 0;
for (int i = 2; i * i <= d; i++) {
if (d % i == 0) {
p[++cnt] = i;
while (d % i == 0) {
d /= i;
a[cnt]++;
}
if (d == 1)return;
}
}
if (d > 1) p[++cnt] = d, a[cnt] = 1;
return;
}
枚举j,计算d的倍数个数
LL p_power[32][32];
LL Cal(LL n, LL m) {
for (int i = 1; i <= cnt; i++) { //预处理,所有p[i]^a[i]
p_power[i][1] = p[i];
for (int j = 2; j <= a[i]; j++)
p_power[i][j] = p_power[i][j - 1] * p[i];
}
int limit = 0; //1-max(a[1]----a[n])的min_d都要单独计算
for (int i = 1; i <= cnt; i++)limit = max(limit, a[i]);
limit = min(LL(limit), m);
int min_d = 1; LL ans = 0;
for (int i = 1; i <= limit; i++) { //枚举j计算
min_d = 1;
for (int j = 1; j <= cnt; j++)
min_d *= p_power[j][ceil(a[j], i)];
ans += n / min_d;
}
if (m > limit)ans += n / min_d * (m - limit);
return ans;
}
AC代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#pragma warning (disable:4996)
typedef long long LL;
#define ceil(a,b) a % b == 0 ? a/b : a/b+1
LL quickpow(LL m, LL p, LL mod) {
LL res = 1;
while (p) {
if (p & 1)
res = res * m % mod;
m = m * m % mod;
p >>= 1;
}
return res;
}
int big_d[32000];
LL Get_Min_d(LL p) {
LL phi = p - 1; int k = 0;
for (int i = 1; i * i <= phi; i++) {
if (phi % i == 0) {
if (quickpow(10, i, p) == 1)
return i;
big_d[++k] = phi / i;
}
}
for (int i = k; i >= 1; i--) {
if (quickpow(10, big_d[i], p) == 1)
return big_d[i];
}
}
int p[32], a[32], cnt;
void Dec(LL d) {
fill(p, p + 32, 0);
fill(a, a + 32, 0); cnt = 0;
for (int i = 2; i * i <= d; i++) {
if (d % i == 0) {
p[++cnt] = i;
while (d % i == 0) {
d /= i;
a[cnt]++;
}
if (d == 1)return;
}
}
if (d > 1) p[++cnt] = d, a[cnt] = 1;
return;
}
LL p_power[32][32];
LL Cal(LL n, LL m) {
for (int i = 1; i <= cnt; i++) {
p_power[i][1] = p[i];
for (int j = 2; j <= a[i]; j++)
p_power[i][j] = p_power[i][j - 1] * p[i];
}
int limit = 0;
for (int i = 1; i <= cnt; i++)limit = max(limit, a[i]);
limit = min(LL(limit), m);
int min_d = 1; LL ans = 0;
for (int i = 1; i <= limit; i++) {
min_d = 1;
for (int j = 1; j <= cnt; j++)
min_d *= p_power[j][ceil(a[j], i)];
ans += n / min_d;
}
if (m > limit)ans += n / min_d * (m - limit);
return ans;
}
int main() {
int t; scanf("%d", &t);
LL p, n, m;
while (t--) {
scanf("%lld%lld%lld", &p, &n, &m);
if (p == 2 || p == 5) {
printf("0\n");
continue;
}
else if (p == 3){
printf("%lld\n", n / 3 * m);
continue;
}
LL d = Get_Min_d(p);
Dec(d);
LL ans = Cal(n, m);
printf("%lld\n", ans);
}
}