bzoj4666 小z的胡话
题目描述:
题解:
乱搞好题哇。
众所周知斐波那契数列是有循环节的。
我们可以搞出在模$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\n",ve[0][0]+1); return 0; }