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

根据一些数学知识可以知道形如 f n = p f n 1 + q f n 2 的数列,设方程 x 2 p x q = 0 存在两实数根为 x 1 , x 2 ,则 f n 可以被表示为 f n = A x 1 n + B x 2 n 的形式,且通过 f 0 , f 1 可以求出 A B 。在本题中取 x 1 = b + d 2 , x 2 = b d 2 , A = B = 1 ,可以求出上文中的 p , q , f 0 , f 1 。通过题目限制可以发现四者都是整数,因此 f n 也是整数。
然后用矩阵乘法做递推即可。最后答案等于 f n x 2 n ,注意到 | x 2 | < 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);
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/82110756