首页 > 代码库 > calc(NOIP模拟赛Round 3)

calc(NOIP模拟赛Round 3)

原题:

D e s c r i p t i o n

给三个正整数n,m和p,求(n^1+...n^m) mod p。 Input

一行,三个整数n,m和p。 Output

输出答案。 S a m p l e  I n p u t

2 2 5

S a m p l e  O u t p u t

1

数 据 范 围

n,p<=10^8    m<=10^17 时 限

1s

首先看到m范围就知道是快速幂了对吧。

然后我们想想看。假如是平常的快速幂的话时间复杂度为O(M)

TLE了对吧,然后我们想想有没有LOG级别的算法,就是加法也做到LOG。

考场上寻找DP式去了。。

a^1+a^2+a^3+a^4=(1+a^2)(a^1+a^2);

所以。。以此类推

f[n]=(1+f[n>>1])%p*f[n>>1]%p;

但是n为奇数的时候显然无法得到这个式子

所以奇数时:

f[n]=f[n-1]+a^n(快速幂)

然后算法复杂度O(logm)

快多啦!

然后就是代码。。

注意!在这道题中所有的数据都要定义为 long long ,否则会挂掉!

就是因为考场上太弱了,写了个int都没发现。我的70分/(ㄒoㄒ)/~~。

下面贴代码

#include<iostream>
#include<cstdio>
using namespace std;
unsigned long long num[500];
unsigned long long n,m,p;
unsigned long long ans;
unsigned long long work(unsigned long long x)
{
    unsigned long long tmp=x;
    unsigned long long qaq=1;
    int tt=1;
    while(tmp)
    {
        if(tmp&1)qaq=(qaq*num[tt])%p;    
        tt++;
        tmp>>=1;
    }
    return qaq;
}
unsigned long long dfs(unsigned long long x)
{
    if(x==1)return n%p;
    if(x==0)return 1;
    if(x%2==0)return (dfs(x/2)%p*(1+work(x/2))%p)%p;
    else return (dfs(x-1)%p+work(x)%p)%p;
}
int main(){
    freopen("calc.in","r",stdin);
    freopen("calc.out","w",stdout);
    scanf("%lld%lld%lld",&n,&m,&p); 
    unsigned long long  sum=1,tot=1;
    num[1]=n;
    while(sum<m){
    num[++tot]=(num[tot-1]*num[tot-1])%p;    
    sum<<=1;
    }
    ans=dfs(m);
    printf("%lld\n",ans);    
    fclose(stdin);
    fclose(stdout);
} 

 

calc(NOIP模拟赛Round 3)