题目大意:
题目链接:https://codeforces.com/problemset/problem/17/D
你有一个本子,你要往上面写全部的长度为
n
n
n的
a
a
a进制数字,每一页可以写
p
p
p个。要求所有数字必须严格不含前导
0
0
0。求最后一页上有多少个数字。
思路:
这道题的范围是
2
≤
a
≤
1
0
1000
,
000
,
1
≤
n
≤
1
0
1000
,
000
,
1
≤
p
≤
1
0
9
2\leq a\leq 10^{1000,000},1\leq n\leq 10^{1000,000},1\leq p\leq 10^9
2≤a≤101000,000,1≤n≤101000,000,1≤p≤109。
一个
a
a
a进制的数字的每一位有
a
a
a种取值,但是题目要求不能有前导0,所以第一位只有
a
−
1
a-1
a−1种取值。
所以满足要求的
a
a
a进制数有
(
a
−
1
)
a
n
−
1
(a-1)a^{n-1}
(a−1)an−1个。
所以题目要求我们求得就是
(
a
−
1
)
a
n
−
1
m
o
d
  
p
(a-1)a^{n-1}\mod\ p
(a−1)an−1mod p
但是当
p
∣
(
a
−
1
)
a
n
−
1
p|(a-1)a^{n-1}
p∣(a−1)an−1时应输出
p
p
p。因为此时最后一页有0个字,相当于这一页没写过,也就不是最后一页了。
a
,
n
a,n
a,n很大,但是
p
≤
1
0
9
p\leq 10^9
p≤109。根据扩展欧拉定理,有
a
n
−
1
≡
a
(
n
−
1
)
m
o
d
φ
(
p
)
+
φ
(
p
)
(
m
o
d
p
)
a^{n-1}\equiv a^{(n-1)\ mod\ \varphi(p)+\varphi(p)}(mod\ p)
an−1≡a(n−1) mod φ(p)+φ(p)(mod p)。所以我们可以把指数用拓展欧拉定理降到
1
0
9
10^9
109以内,然后用快速幂即可。
a
a
a可以边读入边取模。反正
a
b
m
o
d
p
=
(
a
m
o
d
p
)
×
(
b
m
o
d
p
)
m
o
d
p
ab\ mod\ p=(a\ mod\ p)\times (b\ mod\ p)\ mod\ p
ab mod p=(a mod p)×(b mod p) mod p。
时间复杂度
O
(
l
e
n
)
O(len)
O(len)。
代码:
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int N=1000010;
char sa[N],sn[N];
ll p,a,n,phi,q,ans;
int len1,len2;
bool flag;
ll power(ll x,ll k)
{
ll ans=1;
for (;k;k>>=1,x=x*x%p)
if (k&1) ans=ans*x%p;
return ans;
}
int main()
{
scanf("%s %s %lld",sa+1,sn+1,&p);
phi=q=p; len1=strlen(sa+1); len2=strlen(sn+1);
for (ll i=2;i*i<=q;i++)
if (!(q%i))
{
phi=phi/i*(i-1);
while (!(q%i)) q/=i;
}
if (q>1) phi=phi/q*(q-1);
for (int i=1;i<=len1;i++)
a=(a*10+sa[i]-48)%p;
for (int i=len2;i>=1;i--) //n-1
if (sn[i]==48) sn[i]='9';
else
{
sn[i]--;
break;
}
for (int i=1;i<=len2;i++)
{
n=n*10+sn[i]-48;
if (n>=phi) flag=1;
n%=phi;
}
if (flag) n+=phi;
ans=((a-1)*power(a,n)%p+p)%p; //注意这里可能为负数,所以要加p再模p,被HACK了一次
if (ans) printf("%lld",ans);
else printf("%lld",p);
return 0;
}