Codeforces Beta Round #17D Notepad 欧拉降幂

题目传送门:Problem - 17D - Codeforces

Nick is attracted by everything unconventional. He doesn't like decimal number system any more, and he decided to study other number systems. A number system with base b caught his attention. Before he starts studying it, he wants to write in his notepad all the numbers of length n without leading zeros in this number system. Each page in Nick's notepad has enough space for c numbers exactly. Nick writes every suitable number only once, starting with the first clean page and leaving no clean spaces. Nick never writes number 0 as he has unpleasant memories about zero divide.

Would you help Nick find out how many numbers will be written on the last page.

Input

The only input line contains three space-separated integers bn and c (2 ≤ b < 10106, 1 ≤ n < 10106, 1 ≤ c ≤ 109). You may consider that Nick has infinite patience, endless amount of paper and representations of digits as characters. The numbers doesn't contain leading zeros.

Output

In the only line output the amount of numbers written on the same page as the last number.

样例输入:

2 3 3
2 3 4
样例输出:

1

4

题目大意:

        给你一个b进制,求数的长度为n且不含前导0的数的个数,把这些数放在一页容量为c个数的书上,问你最后一页写了几个数,也就是让你数量对c取模,为0时就等于c,输出答案就是。

解题思路:

        根据观察呢,我们不难发现:ans=(b-1)*b^{n-1}%c,当ans为0时,输出c。公式不难推出,但实际运算肯定不能这么算,因为题目给的数据范围太大了,unsigned long long都不一定装的下,此时,我们就要用到欧拉降幂,先贴出欧拉降幂的公式:

 此时当n为十位以内,当然就不用用到欧拉降幂,直接带公式计算就行了,当n为十位以上时,由于底数b极大,c相对于b太小,所以gcd(b,c)\neq 1,用第三个公式就行了(这里我也不知道怎么证明的,此题用第三个公式就过),同时此题输入的b,n,极大,用的是高精度存储,所以需要用到高精度取模运算,即ab%c=a*10%c+b%c,也很好证明,就不说为什么了,看代码。

AC代码:

#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=1e6+10;
char b[N],n[N];
ll c,k;
ll get_date(char *s,ll p)//高精度取余得到数据
{
    ll res=0;
    for (int i=0; i<strlen(s); i++) {
        res=(res*10+s[i]-'0')%p;
    }
    return res;
}
ll phi(ll n)//欧拉函数
{
    ll res=n;
    for (int i=2; i<=n/i; i++) {
        if(n%i==0)
        {
            res=res/i*(i-1);
            while(n%i==0) n/=i;
        }
    }
    if(n>1) res=res/n*(n-1);
    return res;
}
ll qsm(ll a,ll z)
{
    ll res=1;
    while(z)
    {
        if(z&1) res=res*a%c;
        a=a*a%c;
        z>>=1;
    }
    return res;
}
int main()
{
    while(scanf("%s %s%lld",b,n,&c)!=EOF)
    {
        ll ph=phi(c);//求欧拉值
        ll aa=get_date(b, c);//得到底数
        ll k=get_date(n, ph);//得到幂
        ll ans;
        if(strlen(n)<10)//小于十位,直接运算
        {
            ll kk=0;
            for (int i=0; i<strlen(n); i++) kk=kk*10+n[i]-'0';//不做取余,直接算幂
            ans=((aa-1+c)%c*qsm(aa,kk-1)%c)%c;//+c是为了防止乘0,下同
        }else{
            k=(k-1+ph)%ph+ph;//欧拉降幂
            ans=((aa-1+c)%c*qsm(aa,k)%c)%c;
        }
        if(ans) printf("%lld\n",ans);//不为0直接输出
        else printf("%lld\n",c);//为0输出c
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值