[JLOI2015] bzoj 4002 有意义的字符串 - 常系数线性递推

根据一些数学知识可以知道形如fn=pfn1+qfn2的数列,设方程x2pxq=0存在两实数根为x1,x2,则fn可以被表示为fn=Ax1n+Bx2n的形式,且通过f0,f1可以求出AB。在本题中取x1=b+d2,x2=bd2,A=B=1,可以求出上文中的p,q,f0,f1。通过题目限制可以发现四者都是整数,因此fn也是整数。
然后用矩阵乘法做递推即可。最后答案等于fnx2n,注意到|x2|<1,所以最多只有1的误差,特判即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define mod 7528443412579576937ll
#define lint long long
#define ull unsigned long long
using namespace std;
inline lint pls(lint a,lint b) { return (lint)(((ull)a+b)%mod); }
inline lint tms(lint a,lint b,lint ans=0)
{   for(;b;b>>=1,a=pls(a,a)) (b&1ll)?ans=pls(ans,a):0;return ans;   }
struct node{
    lint a,b,c,d;
    node(lint _a=1,lint _b=0,lint _c=0,lint _d=1)
    {   a=_a,b=_b,c=_c,d=_d;    }
    inline node operator=(const node &n)
    {   return a=n.a,b=n.b,c=n.c,d=n.d,*this;   }
    inline node operator*(const node &n)const
    {
        node r;
        r.a=pls(tms(a,n.a),tms(b,n.c)),
        r.b=pls(tms(a,n.b),tms(b,n.d)),
        r.c=pls(tms(c,n.a),tms(d,n.c)),
        r.d=pls(tms(c,n.b),tms(d,n.d));
        return r;
    }
    inline node operator*=(const node &n)
    {   return (*this)=(*this)*n;   }
};
inline node fast_pow(node x,lint k,node ans=node())
{   for(;k;k>>=1,x*=x) (k&1ll)?ans*=x,0:0;return ans;   }
int main()
{
    lint b,d,n;scanf("%lld%lld%lld",&b,&d,&n);
    node t=fast_pow(node(b,(d-b*b)/4%mod,1,0),n);
    lint ans=pls(tms(t.c,b),tms(t.d,2));
    if(n%2==0&&d!=b*b) ans=(lint)((ans-1ull+mod)%mod);
    return !printf("%lld\n",ans);
}

没有更多推荐了,返回首页