BZOJ4294 : [PA2015]Fibonacci(dfs、暴力、数位dp)

解析

新定义数位dp了属于是。

结论:斐波拉契在模 1 0 m 10^m 10m 的意义下循环节为 6*10^m。

但这个不一定是最小循环节,我自己做的时候打表得出来的循环节更小。

考虑从低到高枚举周期中的位置,暴力check合法进行剪枝。
跑的飞快,O(能过)。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define ldb long double
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define Ok debug("OK\n")
using namespace std;

const int N=2e5+100;
const int inf=1e9;
//const int mod=998244353
inline ll read(){
  ll x(0),f(1);char c=getchar();
  while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}
  while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
  return x*f;
}
/*
inline ll ksm(ll x,ll k){
  ll res(1);
  while(k){
    if(k&1) res=res*x%mod;
    x=x*x%mod;
    k>>=1;
  }
  return res;
}*/
inline ull qm(ull x,ull y,ull mod){
  ll r=(ldb)x*y/mod+0.5,res=x*y-mod*r;
  return res<0?res+mod:res;
}
struct matrix{
  int x,y;
  ull a[3][3];
  matrix(int X,int Y):x(X),y(Y){memset(a,0,sizeof(a));}
}tr(2,2),I(2,2);
matrix mul(const matrix &u,const matrix &v,ull mod){
  matrix res(u.x,v.y);
  for(int k=1;k<=u.y;k++){
    for(int i=1;i<=u.x;i++){
      ull tmp=u.a[i][k];
      for(int j=1;j<=v.y;j++){
	res.a[i][j]=(res.a[i][j]+qm(tmp,v.a[k][j],mod))%mod;
      }
    }
  }
  return res;
}
matrix ksm(matrix x,ull k,ull mod){
  matrix ans=I;
  while(k){
    if(k&1) ans=mul(ans,x,mod);
    x=mul(x,x,mod);
    k>>=1;
  }
  return ans;
}
inline ull Fib(int n,ull mod){
  if(n<=0) return 0;
  matrix res(1,2);
  res.a[1][1]=0;
  res.a[1][2]=1;
  res=mul(res,ksm(tr,n,mod),mod);
  return res.a[1][1];
}

int n;
ull mi[20],a[20];
int top;
void dfs(int k,ull n,ull len){
  //printf("k=%d n=%llu Fib=%llu\n",k,n,Fib(n,mi[k]));
  if(Fib(n,mi[k])!=a[k]) return;
  if(k==top){
    //n+=6*mi[18];
    //printf("top=%d Fib=%lld %lld\n",top,Fib(n,mi[k]),a[k]);
    printf("%llu\n",n);exit(0);
  }
  for(int i=0;i<10;i++){
    dfs(k+1,(n+qm(i,len,len*10)%(len*10)),len*10);
  }
  return;
}
inline int calc(ull x){
  int res(0);
  while(x){
    ++res;x/=10;
  }
  return res;
}
char s[50];
signed main(){
#ifndef ONLINE_JUDGE
  freopen("a.in","r",stdin);
  freopen("a.out","w",stdout);
#endif
  tr.a[1][1]=0;tr.a[1][2]=1;
  tr.a[2][1]=1;tr.a[2][2]=1;
  I.a[1][1]=I.a[2][2]=1;
  //for(int i=1;i<=10;i++) printf("%lld\n",Fib(i,998244353));
  scanf(" %s",s+1);top=strlen(s+1);
  mi[0]=1;
  for(int i=1;i<=18;i++) mi[i]=mi[i-1]*10;
  for(int i=1;i<=top;i++) a[i]=a[i-1]+(s[top-i+1]-'0')*mi[i-1];
  //for(int i=1;i<=top;i++) printf("i=%d top=%llu\n",i,a[i]);
  for(int i=1;i<=60;i++) dfs(1,i,60);
  puts("NIE");
  return 0;
}
/*
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值