【CF17D】Notepad【拓展欧拉定理】
题目大意:
题目链接:https://codeforces.com/problemset/problem/17/D
你有一个本子,你要往上面写全部的长度为的进制数字,每一页可以写个。要求所有数字必须严格不含前导。求最后一页上有多少个数字。
思路:
这道题的范围是。
一个进制的数字的每一位有种取值,但是题目要求不能有前导0,所以第一位只有种取值。
所以满足要求的进制数有个。
所以题目要求我们求得就是
但是当时应输出。因为此时最后一页有0个字,相当于这一页没写过,也就不是最后一页了。
很大,但是。根据扩展欧拉定理,有。所以我们可以把指数用拓展欧拉定理降到以内,然后用快速幂即可。
可以边读入边取模。反正。
时间复杂度。
代码:
#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;
}