题目大意:

题目链接:​​https://codeforces.com/problemset/problem/17/D​

你有一个本子,你要往上面写全部的长度为nnn的aaa进制数字,每一页可以写ppp个。要求所有数字必须严格不含前导000。求最后一页上有多少个数字。


思路:

这道题的范围是2≤a≤101000,000,1≤n≤101000,000,1≤p≤1092\leq a\leq 10^{1000,000},1\leq n\leq 10^{1000,000},1\leq p\leq 10^92≤a≤101000,000,1≤n≤101000,000,1≤p≤109。

一个aaa进制的数字的每一位有aaa种取值,但是题目要求不能有前导0,所以第一位只有a−1a-1a−1种取值。

所以满足要求的aaa进制数有(a−1)an−1(a-1)a^{n-1}(a−1)an−1个。

所以题目要求我们求得就是

(a−1)an−1mod   p(a-1)a^{n-1}\mod\ p(a−1)an−1mod p

但是当p∣(a−1)an−1p|(a-1)a^{n-1}p∣(a−1)an−1时应输出ppp。因为此时最后一页有0个字,相当于这一页没写过,也就不是最后一页了。

a,na,na,n很大,但是p≤109p\leq 10^9p≤109。根据扩展欧拉定理,有an−1≡a(n−1) mod φ(p)+φ(p)(mod 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)。所以我们可以把指数用拓展欧拉定理降到10910^9109以内,然后用快速幂即可。

aaa可以边读入边取模。反正ab mod p=(a mod p)×(b mod p) mod pab\ mod\ p=(a\ mod\ p)\times (b\ mod\ p)\ mod\ pab mod p=(a mod p)×(b mod p) mod p。

时间复杂度O(len)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;
}