[pa2015]Fibonacci 解题报告

考虑斐波那契数列模n的循环节,设其长度为L(n)。(这个东西有个学名叫the Pisano period)
显然,若n=pq((p,q)=1),则L(n)=lcm(L(p),L(q))。所以我们就可以将n分解成若干 pk 的乘积考虑。
对于 L(pk) (p是质数,k>1),有一个猜想: L(pk)=L(p)pk1 。(参考资料,据说是一个叫D·D·Wall的人在1960年猜的)
而对于这道题,模2的循环节是3,模5的循环节是20。(我听说对于大于5的质数p的循环节是p-1或2(p+1)的因子)
所以模 10n 的循环节我们就可以搞定了。

然后我们就只需要从低位往高位考虑,一位一位另其相等,dfs下去就可以了。至于时间复杂度。。反正情况应该是比较少的。
代码:

#include<cstdio>
#include<iostream>
using namespace std;
#include<algorithm>
#include<sstream>
#include<cstring>
#include<string>
#include<cstdlib>
typedef long long LL;
const LL S=1e18;
LL mul(LL a,LL b,LL Mod){
    LL ans=0;
    a=(a+Mod)%Mod,b=(b+Mod)%Mod;
    for(;b;b>>=1,a=(a<<1)%Mod)
        if(b&1)
            ans=(ans+a)%Mod;
    return ans;
}
LL ans[2][2],mat[2][2],tmp[2][2];
LL mul(LL a[2][2],LL b[2][2],LL Mod){
    memset(tmp,0,sizeof(tmp));
    for(int i=2;i--;)
        for(int k=2;k--;)
            if(b[i][k])
                for(int j=2;j--;)
                    if(a[k][j])
                        tmp[i][j]=(tmp[i][j]+mul(a[k][j],b[i][k],Mod))%Mod;
    memcpy(a,tmp,sizeof(tmp));
}
LL query(LL n,LL Mod){
    if(n==0)return 0;
    mat[0][0]=mat[0][1]=mat[1][0]=1,mat[1][1]=0;
    ans[0][0]=ans[1][1]=1,ans[0][1]=ans[1][0]=0;
    for(;n;n>>=1,mul(mat,mat,Mod))
        if(n&1)
            mul(ans,mat,Mod);
    return ans[1][0];
}

LL cirlen[20];
stringstream ss;

int len;
void dfs(int x,LL now,LL n,LL prod){
    if(x>len){
        cout<<now+cirlen[len]<<endl;
        exit(0);
    }
    for(int i=0;i<cirlen[x]/cirlen[x-1];++i)
        if(query(now+i*cirlen[x-1],prod*10)/prod==n%10)
            dfs(x+1,now+i*cirlen[x-1],n/10,prod*10);
}
int main(){
    freopen("bzoj_4294.in","r",stdin);
    //freopen("bzoj_4294.out","w",stdout);

    cirlen[0]=1,cirlen[1]=60;
    for(int i=2;i<=3;++i)cirlen[i]=cirlen[i-1]*5;
    for(int i=4;i<=18;++i)cirlen[i]=cirlen[i-1]*10;

    LL n;
    string s;
    cin>>s;
    ss<<s;
    ss>>n;
    len=s.size();
    dfs(1,0,n,1);
    puts("NIE");
}

总结:
L(pk)=L(p)pk1 .

你可能感兴趣的:(数论,DFS,矩阵乘法)