51nod 1643

花了两天磨磨蹭蹭把这题a了。。

显然的, f(n)=i|niϕ(ni) f ( n ) = ∑ i | n i ϕ ( n i ) ,因为 ϕ ϕ 是一个积性函数,故 f f 也是一个积性函数,g(n)也是一个积性函数。

先计算 f(pn) f ( p n ) 的值:
f(pn)=i|pniϕ(pni) f ( p n ) = ∑ i | p n i ϕ ( p n i )
=ni=0pi(pnipni1) = ∑ i = 0 n p i ( p n − i − p n − i − 1 )
=n(pnpn1)+pn = n ( p n − p n − 1 ) + p n

再计算 g(pn) g ( p n ) 的值:
g(pn)=1+ni=1f(pi) g ( p n ) = 1 + ∑ i = 1 n f ( p i )
=ni=0pi+ni=1i(pipi1) = ∑ i = 0 n p i + ∑ i = 1 n i ( p i − p i − 1 )
=ni=0pi+(1+p2p+2p23p2+3p3...+npn) = ∑ i = 0 n p i + ( − 1 + p − 2 p + 2 p 2 − 3 p 2 + 3 p 3 . . . + n p n )
=ni=0pin1i=0pi+npn = ∑ i = 0 n p i − ∑ i = 0 n − 1 p i + n p n
=(n+1)pn = ( n + 1 ) p n

回到问题,注意到 c c 的范围只有107 xi x i 的循环节长度必然不会超过 c c 的范围。故先处理出循环节内的所有数,并计算出循环节的长度、循环节前面多余部分的长度以及在最后一个循环节中剩余部分的长度,并以此处理出每个数的出现次数。

z(i)表示 i i 的出现次数,我们从大到小计算,设p i i 的最小素因子,那么:
z(p)=z(p)+z(i),我们将 i i 产生的p计数;
z(ip)=z(ip)+z(i) z ( i p ) = z ( i p ) + z ( i ) ,剩下的我们弄到 ip i p 处理。

因为 z z 可能会爆longlong,所以我维护了模109+7 z z 和模109+6 z z 。。

以此我们可以在O(c)下计算出所有素数的出现次数,最后逐个计算即可。
时间复杂度 O(c+64clogc) O ( c + 64 c l o g c ) ?(乱算的)

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
//Container--
#include<unordered_map>
#include<map>
//
#define clr(a) memset(a,0,sizeof(a))
typedef long long ll;const ll md=1e9+7;const int up=1e7,sup=670000;
int mi[up+10],pn,pr[sup],cq[up+10][2];ll m;int da,db,dc,x1;

inline ll qni(ll a,ll b){
    ll r=1;for(;b;b>>=1,a=a*a%md)if(b&1)r=r*a%md;return r;
};

void init(){
    int i,j,k,d,t;for(pn=0,i=2;i<=up;++i){
        if(!cq[i][0]){pr[pn++]=i;mi[i]=i;}
        for(j=0;j<pn&&(ll)pr[j]*i<=up;++j){
            mi[pr[j]*i]=pr[j],cq[pr[j]*i][0]=1;
            if(!(i%pr[j]))break;
        }
    }
    clr(cq);
};

ll _cl(int p,ll x,ll dx){
    ll z=qni(p,x);
    return (dx+1)*z%md;
};

void cl(){
    scanf("%lld %d %d %d %d",&m,&x1,&da,&db,&dc);
    int i,j,k,d,t,lq,lm,lr;
    for(init(),lm=0,i=x1;;i=((ll)i*da+db)%dc+1){
        if(cq[i][0]){
            lm=lm-cq[i][0]+1;
            lq=cq[i][0]-1;
            break;
        }
        cq[i][0]=++lm;
    }
    lr=m<=lq?0:((m-lq)%lm);
    for(i=2;i<=up;++i)if(cq[i][0]){
        if(cq[i][0]<=lq)cq[i][0]=cq[i][1]=1;
        else{
            if(m<=lq)cq[i][0]=cq[i][1]=0;
            else{
                if(cq[i][0]-lq<=lr)cq[i][0]=((m-lq)/lm+1)%(md-1),cq[i][1]=((m-lq)/lm+1)%md;
                else
                    cq[i][0]=(m-lq)/lm%(md-1),cq[i][1]=(m-lq)/lm%md;
            }
        }
    }
    for(i=up;i>1;--i)if(mi[i]!=i){
        cq[mi[i]][0]=((ll)cq[mi[i]][0]+cq[i][0])%(md-1);
        cq[mi[i]][1]=((ll)cq[mi[i]][1]+cq[i][1])%md;
        cq[i/mi[i]][0]=((ll)cq[i/mi[i]][0]+cq[i][0])%(md-1);
        cq[i/mi[i]][1]=((ll)cq[i/mi[i]][1]+cq[i][1])%md;
    }
    ll rs=1;for(i=0;i<pn;++i)rs=rs*_cl(pr[i],cq[pr[i]][0],cq[pr[i]][1])%md;
    printf("%lld\n",rs);
};

int main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
#endif
    cl();
    return 0;
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值