1. 程式人生 > >BZOJ_4002_[JLOI2015]有意義的字符串_矩陣乘法

BZOJ_4002_[JLOI2015]有意義的字符串_矩陣乘法

!= long clas mat img ont == memset tput

BZOJ_4002_[JLOI2015]有意義的字符串_矩陣乘法

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


$通過通項式可以求出遞推式,具體的,
有遞推式Ax_n+Bx_{n-1}+Cx_{n-2}=0$

$用Ax^{2}+Bx+C=0解出x_1,x_2,那麽通項為S_n=(k_1*x_1)^{n}+(k_2*x_2)^{n}$

$首先設S_n=(\frac{b+\sqrt{d}}{2})^{n}+(\frac{b-\sqrt{d}}{2})^{n}$

$x_1=\frac{b+\sqrt{d}}{2},x_2=\frac{b-\sqrt{d}}{2}$

$A=1,B=b,C=\frac{b^{2}-d}{4}$

$之後就可以用矩陣乘法求S_n了,並且我們發現(\frac{b-\sqrt{d}}{2})^{n}的取值為[-1,1]$


$它對答案有貢獻當且僅當n為偶數,b\not=\sqrt{d}$

代碼:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;
typedef unsigned long long ll;
typedef double du;
ll mod=7528443412579576937ll,b,d,n;
ll qc(ll x,ll y) {
    ll re=0;
    while(y>=1) {
        if(y&1ll) re=(re+x)%mod;
        x=(x+x)%mod;
        y>>=1ll;
    }
    return re;
}
struct Mat {
    ll v[2][2];
    Mat(){memset(v,0,sizeof(v));}
    Mat operator*(const Mat &x)const {
        Mat re;int i,j,k;
        for(i=0;i<2;i++) {
            for(j=0;j<2;j++) {
                for(k=0;k<2;k++) {
                    re.v[i][j]=(re.v[i][j]+qc(v[i][k],x.v[k][j]))%mod;
                }
            }
        }
        return re;
    }
};
Mat qp(Mat x,ll y) {
    Mat I;
    I.v[0][0]=I.v[1][1]=1;
    while(y>=1) {
        if(y&1ll) I=I*x;
        x=x*x;
        y>>=1ll;
    }
    return I;
}
int main() {
    scanf("%llu%llu%llu",&b,&d,&n);
    Mat x;
    x.v[0][0]=0; x.v[0][1]=(d-b*b)/4; x.v[1][0]=1; x.v[1][1]=b;
    Mat T=qp(x,n);
    ll ans=(qc(2,T.v[0][0])+qc(b,T.v[1][0]))%mod;
    if(d!=b*b&&n%2==0) ans--;
    printf("%llu\n",ans);
}

BZOJ_4002_[JLOI2015]有意義的字符串_矩陣乘法