【2019牛客暑期多校训练营(第五场)B题】generator 1(广义斐波那契数列循环节+积性函数)

思路:

形如f(n)=af(n-1)+bf(n-2)的数列就叫做广义斐波那契数列。

设g(x)为mo=x时的f(n)的循环节,即f(n)\equivf(n%g(x))   (mod x),

则g(x)是一个积性函数。

g(x)=\left\{\begin{matrix} (x+1)*(x-1) & x \in \mathbb{P}\\ g(\frac{x}{p_i})*p_i & x\notin \mathbb{P} , p_i^2|x\\ g(\frac{x}{p_i})*g(p_i) & x\notin \mathbb{P} ,p_i|x,gcd(pi,\frac{x}{p_i})=1 \end{matrix}\right.

=\prod g(p_i) * \frac{x}{\prod p_i}

=phi(x)*\prod (p_i+1)

x为质数时的证明

ps:x不是质数时的结论是下午做题时的猜想,不保证正确性。可以过这个题,但是万一是水过的呢,之后还会再跑程序验证下。

代码:

#include<cstdio>
#include<cstring>
typedef long long ll;
const int N=1000000+10;
struct Node{
    int r,c;
    ll jz[3][3];
    Node(){
        memset(jz,0,sizeof(jz));
    }
};
ll x0,x1,a,b,n,md,mmd;
char s[N];
int pn,pri[100000+10];
void init(){
    ll lim;
    for(int i=2;i<=100000;i++){
        if(!pri[i]) pri[pn++]=i;
        for(int j=0;j<pn;j++){
            lim=1ll*i*pri[j];
            if(lim>100000) break;
            pri[lim]=1;
            if(i%pri[j]==0) break; 
        }
    }
}
ll solve(ll x){
    ll ans1=1,ans2=1,xx=x;
    for(int i=0;i<pn;i++){
        if(1ll*pri[i]*pri[i]>x) break;
        if(x%pri[i]==0){
            ans1*=(pri[i]-1)*(pri[i]+1);
            ans2*=pri[i];
            while(x%pri[i]==0) x/=pri[i];
        }
    }
    if(x>1){
        ans1*=(x-1)*(x+1);
        ans2*=x;
    }
    return xx/ans2*ans1;
}
ll mul(ll x,ll y,ll z){
    x%=z;
    y%=z;
    ll ans=0;
    while(y){
        if(y&1){
            ans+=x;
            if(ans>=z) ans-=z;
        }
        x<<=1;
        if(x>=z) x-=z;
        y>>=1;
    }
    return ans;
}
Node Nmul(Node x,Node y,ll z){
    Node ans;
    ans.r=x.r;
    ans.c=y.c;
    for(int i=0;i<x.r;i++)
        for(int j=0;j<y.c;j++)
            for(int k=0;k<x.c;k++){
                ans.jz[i][j]+=mul(x.jz[i][k],y.jz[k][j],z)%z;
                if(ans.jz[i][j]>=z) ans.jz[i][j]%=z;
            }
    return ans;
}
Node Npow(Node x,ll y,ll z){
    Node ans;
    ans.r=x.r;
    ans.c=x.c;
    for(int i=0;i<ans.c;i++) ans.jz[i][i]=1;
    while(y){
        if(y&1) ans=Nmul(ans,x,z);
        x=Nmul(x,x,z);
        y>>=1;
    }
    return ans;
}
int main(){
    init();
    while(~scanf("%lld%lld%lld%lld",&x0,&x1,&a,&b)){
        scanf("%s%lld",s,&md);
        mmd=solve(md);
        n=0;
        int lens=strlen(s);
        for(int i=0;i<lens;i++){
            n=mul(n,10,mmd)+s[i]-'0';
            if(n>=mmd) n-=mmd;
        }
        Node A,T;
        A.r=2;
        A.c=1;
        A.jz[0][0]=x1;
        A.jz[1][0]=x0;
        T.r=2;
        T.c=2;
        T.jz[0][0]=a;
        T.jz[0][1]=b;
        T.jz[1][0]=1;
        if(n>1){
            T=Npow(T,n-1,md);
            A=Nmul(T,A,md);
        }
        printf("%lld\n",A.jz[0][0]);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值