2016多校联赛 hdu 5728 PowMod

来源:互联网 发布:便携咖啡杯 知乎 编辑:程序博客网 时间:2024/06/10 20:04
题意就是题目上的图的那个样子。给定的n是一个n

 is a square-free number. 他是一个无平方因子数。也就是说他分解质因子后质因子的指数是1.


解决这个题分两步,先说第二步,第二步是 bzoj 3884原题,只是在这个题我们需要算底数是多少而已。


引用一下别人的证明(本人巨菜)

考虑欧拉定理,当(a,p)=时,aϕ(p)1(modp)。 
而由此可以很容易得出一个结论: 
xϕ(p)时,有

axaxmodϕ(p)+ϕ(p)(modp)

若令f(p)=222...modp,则f(1)=0。 
又由于是无穷的式子,222...的指数本来就是超过ϕ(p)的,所以我们可以改写成

f(p)=2(22...modϕ(p))+ϕ(p)modp=2f(ϕ(p))+ϕ(p)modp

因而得到了f(p)的递推式。

似乎这么计算是O(p)的,但是我们可以对ϕ(ϕ(...ϕ(p)))进行分析: 
p为偶数,则ϕ(p)p2
p为奇数,则p存在一个奇数因子q,使得ϕ(p)存在一个偶数因子(q1),转化为偶数的情况。 
由此可知,ϕ(ϕ(...ϕ(p)))的计算经过O(logp)次的迭代就到了1,所以f(p)的计算是O(plogp)的。



然后我们来到第一步:解决这个问题,我们需要知道几个性质

对于质数p,φ(p) = p - 1。注意φ(1)=1.

欧拉定理:对于互质的正整数a和n,有aφ(n) ≡ 1 mod n。

欧拉函数是积性函数——若m,n互质,φ(mn)=φ(m)φ(n)。

 若n是质数p的k次幂,φ(n)=p^k-p^(k-1)=(p-1)p^(k-1),因为除了p的倍数外,其他数都跟n互质。



因为此题时间的限制,我们只能筛选10^7以内的所有素数,在求素数的时候顺便就求出欧拉函数,再求出前n项和。

我们来看,如果m是10^7次方,n也是10^7(当然n不可能是10^7),那么我们就希望看能不能把这个i*n的数字变小,变小就有两个方法,把n变小,把m变小。


对于φ (i*n)来说,我们可以令n=x*pri,对于i*n的欧拉值就是求φ(i*x*pri,如果pri和i互质,就是积性的,就可以把pri提出去,φ(i*x)*(pri-1);如果i有因子p的话,我们就可以把m缩小,让m/p为上线, 不变n。依次递推。

当m等于1的时候,那么最终的值就是n的欧拉函数值,当n等于1的时候,就是前m个的欧拉函数值的和。


最方便的情况是先把n素因子分解,然后一个一个用就是咯。

#include<cstdio>#include<cstdlib>#include<cstring>#include<map>#include<cmath>#include<iostream>#include<algorithm>using namespace std;typedef long long ll;const ll mod=1e9+7;const int maxn=1e7;const int maxm=1e5*7;ll prime[maxm+10];bool isprime[maxn+10];ll phi[maxn+10];ll sphi[maxn+10];ll index[50];//ll sphi[maxn+10];int cnt;map<ll,ll>mp;int res;void init(){    cnt=0;    phi[1]=1;    sphi[1]=1;    for(ll i=2; i<=maxn; i++)    {        if(!isprime[i])        {            prime[cnt++]=i;            phi[i]=i-1;        }        for(ll j=0; j<cnt&&i*prime[j]<=maxn; j++)        {            isprime[i*prime[j]]=true;            if(i%prime[j]==0)            {                phi[i*prime[j]]=phi[i]*prime[j];                break;            }            else                phi[i*prime[j]]=phi[i]*(prime[j]-1);        }        sphi[i]=(sphi[i-1]+phi[i])%mod;    }}ll n,m;ll p;ll k;ll mul(ll a,ll b,ll o){    ll ans=1;    while(b)    {        if(b&1)            ans=(ans*a)%o;        b>>=1;        a=(a*a)%o;    }    return ans;}ll Phi(ll x){    ll ret = x;    for(ll i = 2; i * i <= x; ++i)        if(x % i == 0)        {            ret -= ret / i;            while(x % i == 0)                x /= i;        }    if(x > 1)        ret -= ret / x;    return ret;}ll f(ll x){    if(mp.count(x))        return mp[x];    ll c=phi[x];    return mp[x]=(mul(k,f(c)+c,x))%x;}ll sovle(int id,ll n,ll m){//    printf("%d %lld %lld\n",id,n,m);//    getchar();//    if(m==1)//        return phi[n];//    //printf("sssss");    if(n==1)        return sphi[m];    if(m==0)        return 0;    if(id==-1)///没有什么用,因为测不合法的数据要停止工作,不爽        return 0;    return ((sovle(id-1,n/index[id],m)*(index[id]-1))%mod+sovle(id,n,m/index[id]))%mod;}void fen(ll n){    //printf("%d\n",cnt);    for(int i=0; i<cnt; i++)    {        if(!isprime[n])        {            index[res++]=n;            break;        }        if(n%prime[i]==0)        {            index[res++]=prime[i];            n/=prime[i];        }    }}int main(){    init();    //printf("%d\n",cnt);    //cout<<sphi[5]<<endl;    while(~scanf("%lld%lld%lld",&n,&m,&p))    {        mp.clear();        k=0;        res=0;        fen(n);        res--;        //printf("%d\n",res);        k=(k+sovle(res,n,m))%mod;       // printf("%lld\n",k);        printf("%lld\n",f(p));    }}




0 0
原创粉丝点击