列表

详情


NC17631. [NOI2011]兔农

描述

农夫栋栋近年收入不景气,正在他发愁如何能多赚点钱时,他听到隔壁的小朋友在讨论兔子繁殖的问题。 
问题是这样的:第一个月初有一对刚出生的小兔子,经过两个月长大后,这对兔子从第三个月开始,每个月初生一对小兔子。新出生的小兔子生长两个月后又能每个月生出一对小兔子。问第n个月有多少只兔子? 
聪明的你可能已经发现,第n个月的兔子数正好是第n个Fibonacci(斐波那契)数。栋栋不懂什么是Fibonacci数,但他也发现了规律:第i+2个月的兔子数等于第i个月的兔子数加上第i+1个月的兔子数。前几个月的兔子数依次为: 1 1 2 3 5 8 13 21 34 … 
栋栋发现越到后面兔子数增长的越快,期待养兔子一定能赚大钱,于是栋栋在第一个月初买了一对小兔子开始饲养。 
每天,栋栋都要给兔子们喂食,兔子们吃食时非常特别,总是每k对兔子围成一圈,最后剩下的不足k对的围成一圈,由于兔子特别害怕孤独,从第三个月开始,如果吃食时围成某一个圈的只有一对兔子,这对兔子就会很快死掉。 
我们假设死去的总是刚出生的兔子,那么每个月的兔子数仍然是可以计算的。例如,当k=7时,前几个月的兔子数依次为: 1 1 2 3 5 7 12 19 31 49 80 … 
给定n,你能帮助栋栋计算第n个月他有多少对兔子么?由于答案可能非常大,你只需要告诉栋栋第n个月的兔子对数除p的余数即可。

输入描述

输入一行,包含三个正整数n, k, p。

输出描述

输出一行,包含一个整数,表示栋栋第n个月的兔子对数除p的余数。

示例1

输入:

6 7 100

输出:

7

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 319ms, 内存消耗: 42460K, 提交时间: 2020-05-05 19:42:10

#include<bits/stdc++.h>
using namespace std;
const int N=1000010;
long long n,k,p,vis[N],f[N*6],ni[N],len[N];
bool ext[N];
void exgcd(long long a,long long b,long long&x,long long &y,long long &d)
{
    if(b==0) 
	{
		d=a;
		x=1;
		y=0;
	}
    else 
	{
		exgcd(b,a%b,y,x,d);
		y-=x*(a/b);
	}
}
inline long long inv(long long a,long long mod)
{
    long long d,x,y;
	exgcd(a,mod,x,y,d);
    return d==1?(x+mod)%mod:-1;
}
struct marx
{
    long long m[4][4];
    marx(){}
    inline long long *operator [](long long x){return m[x];}
    inline void clear(){memset(m,0,sizeof(m));}
    marx operator * (const marx &b) const
    {
        marx c;c.clear();
        for(int k=1;k<=3;k++)
            for(int i=1;i<=3;i++)
                for(int j=1;j<=3;j++)
                    c.m[i][j]=(c.m[i][j]%p+m[i][k]%p*b.m[k][j]%p)%p;
        return c;
    }
};
marx mat[N],A,B,C,ans;
inline marx poww(marx x,long long len)
{
    marx ret;
	ret.clear();
    ret[1][1]=ret[2][2]=ret[3][3]=1;
    while(len)
    {
        if(len&1) ret=ret*x;
        len>>=1;
		x=x*x;
    }
    return ret;
}
int main()
{
	cin>>n>>k>>p;
    f[1]=f[2]=1;
    for(int i=3; ;i++)
    {
        f[i]=(f[i-1]+f[i-2])%k;
        if(!vis[f[i]]) vis[f[i]]=i;
        if(f[i]==f[i-1]&&f[i]==1) break;
    }
    A[1][1]=A[1][2]=A[2][1]=A[3][3]=1;
    B[1][1]=B[2][2]=B[3][3]=1;
	B[3][1]=-1;
    ans[1][2]=ans[1][3]=1;
    long long x=1;
	bool flag=0;
    while(n)
    {
        if(!ni[x]) ni[x]=inv(x,k);
        if(ni[x]==-1) 
		{
			ans=ans*poww(A,n);
			n=0;
		}
        else if(!ext[x]||flag)
             {
                 ext[x]=1;
                 if(!vis[ni[x]]) ans=ans*poww(A,n),n=0;
                 else
                 {
                     len[x]=vis[ni[x]];
                     if(n>=len[x])
                     {
                         n-=len[x];
                         mat[x]=poww(A,len[x])*B;
                         ans=ans*mat[x];
		 				 x=x*f[len[x]-1]%k;
                     }
                     else 
					 {
						 ans=ans*poww(A,n);
						 n=0;
					 }
                 }
             }
             else
             {
                 long long cnt=0;
                 C.clear();
			 	 C[1][1]=C[2][2]=C[3][3]=1;
                 for(long long i=x*f[len[x]-1]%k;i!=x;i=i*f[len[i]-1]%k)
                     cnt+=len[i],C=C*mat[i];
                 cnt+=len[x];
				 C=mat[x]*C;
                 ans=ans*poww(C,n/cnt);
                 n%=cnt;
				 flag=1;
             }
    }
    cout<<(ans[1][1]%p+p)%p<<endl;
	return 0;
}

C++(clang++ 11.0.1) 解法, 执行用时: 118ms, 内存消耗: 42448K, 提交时间: 2022-09-04 18:53:21

#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int N=1000010;
LL n,k,p,vis[N],f[N*6],ni[N],len[N];
bool ext[N];
void exgcd(LL a,LL b,LL&x,LL &y,LL &d){
    if(b==0)d=a,x=1,y=0;
    else exgcd(b,a%b,y,x,d),y-=x*(a/b);
}
inline LL inv(LL a,LL mod){
    LL d,x,y;exgcd(a,mod,x,y,d);
    return d==1?(x+mod)%mod:-1;
}
struct marx{
    LL m[4][4];
    marx(){}
    inline LL *operator [](LL x){return m[x];}
    inline void clear(){memset(m,0,sizeof(m));}
    marx operator * (const marx &b) const{
        marx c;c.clear();
        for(int k=1;k<=3;k++)for(int i=1;i<=3;i++)for(int j=1;j<=3;j++)c.m[i][j]=(c.m[i][j]%p+m[i][k]%p*b.m[k][j]%p)%p;
        return c;
    }
}mat[N],A,B,C,ans;
inline marx poww(marx x,LL len){
    marx ret;ret.clear();
    ret[1][1]=ret[2][2]=ret[3][3]=1;
    while(len){
        if(len&1)ret=ret*x;
        len>>=1;x=x*x;
    }
    return ret;
}
int main(){
    scanf("%lld%lld%lld",&n,&k,&p);
    f[1]=f[2]=1;
    for(int i=3;;i++){
        f[i]=(f[i-1]+f[i-2])%k;
        if(!vis[f[i]])vis[f[i]]=i;
        if(f[i]==f[i-1]&&f[i]==1)break;
    }
    A[1][1]=A[1][2]=A[2][1]=A[3][3]=1;
    B[1][1]=B[2][2]=B[3][3]=1,B[3][1]=-1;
    ans[1][2]=ans[1][3]=1;
    LL x=1;bool flag=0;
    while(n){
        if(!ni[x])ni[x]=inv(x,k);
        if(ni[x]==-1)ans=ans*poww(A,n),n=0;
        else{
            if(!ext[x]||flag){
                ext[x]=1;
                if(!vis[ni[x]])ans=ans*poww(A,n),n=0;
                else{
                    len[x]=vis[ni[x]];
                    if(n>=len[x]){
                        n-=len[x];
                        mat[x]=poww(A,len[x])*B;
                        ans=ans*mat[x],x=x*f[len[x]-1]%k;
                    }
                    else ans=ans*poww(A,n),n=0;
                }
            }else{
                LL cnt=0;
                C.clear();C[1][1]=C[2][2]=C[3][3]=1;
                for(LL i=x*f[len[x]-1]%k;i!=x;i=i*f[len[i]-1]%k)
                    cnt+=len[i],C=C*mat[i];
                cnt+=len[x],C=mat[x]*C;
                ans=ans*poww(C,n/cnt);
                n%=cnt,flag=1;
            }
        }
    }
    printf("%lld",(ans[1][1]%p+p)%p);
    return 0;
}

上一题