【CF17D】Notepad【拓展欧拉定理】

题目大意:

题目链接: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 2a101000,000,1n101000,000,1p109
一个 a a a进制的数字的每一位有 a a a种取值,但是题目要求不能有前导0,所以第一位只有 a − 1 a-1 a1种取值。
所以满足要求的 a a a进制数有 ( a − 1 ) a n − 1 (a-1)a^{n-1} (a1)an1个。
所以题目要求我们求得就是
( a − 1 ) a n − 1 m o d      p (a-1)a^{n-1}\mod\ p (a1)an1mod p
但是当 p ∣ ( a − 1 ) a n − 1 p|(a-1)a^{n-1} p(a1)an1时应输出 p p p。因为此时最后一页有0个字,相当于这一页没写过,也就不是最后一页了。
a , n a,n a,n很大,但是 p ≤ 1 0 9 p\leq 10^9 p109。根据扩展欧拉定理,有 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) an1a(n1) 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值