[JLOI2015]有意义的字符串
4002: [JLOI2015]有意义的字符串
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1000 Solved: 436
[Submit][Status][Discuss]
Description
B 君有两个好朋友,他们叫宁宁和冉冉。有一天,冉冉遇到了一个有趣的题目:输入 b;d;n,求
Input
一行三个整数 b;d;n
Output
一行一个数表示模 7528443412579576937 之后的结果。
Sample Input
1 5 9
Sample Output
76
HINT
其中 0<b^2< = d<(b+1)2< = 10^18,n< = 10^18,并且 b mod 2=1,d mod 4=1
一开始幼稚的以为可以把sqrt(d)在%7528443412579576937 同余系下表示成一个整数,但后来发现我太naive了。
可以先找到((b+sqrt(d))/2)^n的共轭函数((b-sqrt(d))/2)^n,设这两者的和为f[n]。
那么我们相当于知道了两个基底等比数列,来构造出f[i]的递推式。
显然两个基底的只能是和前两项有关,于是我们设f[i+2]+ k * f[i+1] + p * f[i] =0
那么,可以得到 x^2 + k*x + p =0。
这个方程的两个根分别是 (b+sqrt(d))/2 和 (b-sqrt(d))/2
所以我们带回去就可以求得k和p。
然后就可以开开心心的 用矩阵快速幂求 f[n]了。
但问题是怎么减去共轭函数的另一支呢?
有一个结论是当且仅当 b==d^2且n为偶数的时候需要-1,但是我也不知道为什么2333。
#include<bits/stdc++.h> #define ll unsigned long long using namespace std; const ll ha=7528443412579576937ll; inline ll add(ll x,ll y){ x+=y; return x>=ha?x-ha:x; } inline ll ksc(ll x,ll y){ ll an=0; for(;y;y>>=1,x=add(x,x)) if(y&1) an=add(an,x); return an; } inline ll ksm(ll x,ll y){ ll an=1; for(;y;y>>=1,x=ksc(x,x)) if(y&1) an=ksc(an,x); return an; } const ll inv=ksm(2,ha-2); const ll INV=ksc(inv,inv); ll B,D,N; struct node{ ll a[2][2]; node operator *(const node &u)const{ node r; for(int i=0;i<=1;i++) for(int j=0;j<=1;j++){ r.a[i][j]=add(ksc(a[i][0],u.a[0][j]),ksc(a[i][1],u.a[1][j])); } return r; } }ans,x; inline void solve(){ ans.a[0][0]=ans.a[1][1]=1; ans.a[0][1]=ans.a[1][0]=0; ll O=N; N--; for(;N;N>>=1,x=x*x) if(N&1) ans=ans*x; ll an=0; an=add(ksc(2,ans.a[0][1]),ksc(B,ans.a[1][1])); if(ksc(B,B)!=D&&!(O&1)) an=add(an,ha-1); printf("%lld\n",an); } int main(){ scanf("%lld%lld%lld",&B,&D,&N); if(!N){ puts("1"); return 0; } x.a[0][0]=0; x.a[1][0]=1; x.a[1][1]=B; x.a[0][1]=(D-ksc(B,B))>>2; solve(); return 0; }
我爱学习,学习使我快乐