• bzoj4666 小z的胡话


    题目描述:

    bz

    题解:

    乱搞好题哇。

    众所周知斐波那契数列是有循环节的。

    我们可以搞出在模$10^x$下与所给得数同余的集合,那么在模$10^{x+1}$下,同余集合一定是原集合及循环若干循环节的大集合的子集。

    人话是,i have a xunhuanjie, i have a jihe.EN!another jihe and another xunhuanjie.

    然后矩乘求值判定就好了。

    代码:

    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    ll MOD;
    void Mod(ll&x){if(x>=MOD)x-=MOD;}
    ll fastadd(ll a,ll b)
    {
        ll t = (long double)a*b/MOD;
        ll ret = a*b-t*MOD;
        while(ret<0)ret+=MOD;
        return ret;
    }
    struct mt
    {
        ll s[2][2];
        void reset(ll k)
        {
            s[0][1]=s[1][0]=0;
            s[0][0]=s[1][1]=k;
        }
        void init()
        {
            s[0][0]=s[0][1]=s[1][0]=1;
            s[1][1]=0;
        }
        bool check()
        {
            for(int i=0;i<=1;i++)for(int j=0;j<=1;j++)
                if(s[i][j]!=(i==j))return 0;
            return 1;
        }
        mt operator * (const mt&a)const
        {
            mt ret;ret.reset(0);
            for(int i=0;i<=1;i++)
                for(int j=0;j<=1;j++)
                    for(int k=0;k<=1;k++)
                        Mod(ret.s[i][j]+=fastadd(s[i][k],a.s[k][j]));
            return ret;
        }
    };
    mt operator ^ (mt&x,ll y)
    {
        mt ret;ret.reset(1);
        while(y)
        {
            if(y&1)ret=ret*x;
            x=x*x;y>>=1;
        }
        return ret;
    }
    ll n,L[2];
    vector<ll>ve[2];
     
    int main()
    {
        scanf("%lld",&n);
        L[1] = 1,ve[1].push_back(0),MOD = 1;
        mt bas;bas.reset(1);
        for(int i=1;i<=13;i++)
        {
            MOD=MOD*10;
            mt now;now.init();now=now^L[i&1];
            L[!(i&1)]=0,ve[!(i&1)].clear();
            mt nxt;nxt.reset(1);
            while(!L[!(i&1)]||!nxt.check())
            {
                for(int j=0,lim=(int)ve[i&1].size();j<lim;j++)
                {
                    mt tmp;tmp.init();tmp=tmp^(ve[i&1][j]+L[!(i&1)]);
                    if(tmp.s[0][0]==n%MOD)ve[!(i&1)].push_back(ve[i&1][j]+L[!(i&1)]);
                }
                L[!(i&1)]+=L[i&1];nxt=nxt*now;
            }
        }
        if(!ve[0].size())puts("-1");
        else printf("%lld
    ",ve[0][0]+1);
        return 0;
    }
    View Code
  • 相关阅读:
    过往总结
    查找光标处的标识符
    【转】Linux 内核开发 Eclipse内核开发环境搭建
    【转】Writing linux kernel code in Eclipse
    【转】 Linux内核升级指南
    [转]Ubuntu 11.04 安装后要做的20件事情
    【转】vim 替换操作大全
    【转】移动硬盘安装ubuntu
    重置 Winsock 目录
    【转】让Firefox像vim一样操作
  • 原文地址:https://www.cnblogs.com/LiGuanlin1124/p/11059584.html
Copyright © 2020-2023  润新知