bzoj 4666
Posted zhangleo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 4666相关的知识,希望对你有一定的参考价值。
玄学题...
首先,如果$f_i\equiv a$ $mod$ $10^y$,那么一定有$f_i\equiv a$ $mod$ $10^y-1$
据此我们可以只找出满足$f_i\equiv a$ $mod$ $10^y-1$的项,然后向上检验即可
可是这样的项是无穷的啊
斐波那契数列在模意义下有循环节,且$10^y$的循环节长度一定是$10^y-1$循环节长度的整数倍
这样我们按循环节长度枚举就好了
代码:
#include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #include <queue> #include <stack> #define ll long long using namespace std; ll mode,len; ll pow_add(ll x,ll y) ll ret=0; while(y) if(y&1)ret=(ret+x)%mode; x=(x+x)%mode,y>>=1; return ret; struct MAT ll a[2][2]; friend MAT operator * (MAT x,MAT y) MAT ret; memset(ret.a,0,sizeof(ret.a)); for(int i=0;i<=1;i++)for(int j=0;j<=1;j++)for(int k=0;k<=1;k++)ret.a[i][j]=(ret.a[i][j]+pow_add(x.a[i][k],y.a[k][j]))%mode; return ret; MAT pow_mul(MAT x,ll y) MAT ret; ret.a[0][0]=ret.a[1][1]=1; ret.a[1][0]=ret.a[0][1]=0; while(y) if(y&1)ret=ret*x; x=x*x,y>>=1; return ret; f,g,ori,t; ll q; vector <ll> ans,tempans; int main() freopen("words.in","r",stdin); freopen("words.out","w",stdout); scanf("%lld",&q); mode=len=1; ans.push_back(0); ori.a[0][0]=ori.a[1][0]=ori.a[0][1]=1; for(int i=1;i<=13;i++) mode*=10; f=f.pow_mul(ori,0),g=g.pow_mul(ori,len); ll templen=0; do for(int j=0;j<ans.size();j++) if(t.pow_mul(ori,ans[j]+templen).a[0][1]==q%mode)tempans.push_back(ans[j]+templen); f=f*g,templen+=len; while(f.a[0][0]!=1||f.a[1][0]!=0||f.a[0][1]!=0|f.a[1][1]!=1); ans=tempans,tempans.clear(),len=templen; if(ans.empty())printf("-1\n"); else printf("%lld\n",ans[0]); return 0;
以上是关于bzoj 4666的主要内容,如果未能解决你的问题,请参考以下文章
考后反思(bzoj3940 bzoj4899 bzoj3307)