【bzoj4002】有意義的字符串
Portal --> bzoj4002
Solution
? 雖然說這題有點強行但是感覺還是挺妙的,給你通項讓你反推數列的這種==有點毒
?? 補檔時間
? 首先有一個東西叫做特征方程,我們可以用這個東西來求二階線性遞推數列的通項:
?? 對於數列\(\{x_n\}\),遞推公式為\(x_n=a_1x_{n-1}-a_2x_{n-2}\),那麽這個數列的特征方程為:
\[
x^2-a_1x+a_2=0
\]
? 如果說這個方程有兩個相異的根\(p,q\),那麽:
\[
\begin{aligned}
A&=\frac{x_2-qx_1}{p(p-q)}\B&=\frac{px_1-x_2}{q(p-q)}\x_n&=Ap^n+Bq^n
\end{aligned}
\]
?? 如果有兩個相等的根\(p\),那麽:
\[ \begin{aligned} A=\frac{px_1-x_2}{p^2}\B=\frac{x_2-px_1}{p^2}\x_n=(A+Bn)p^n \end{aligned} \]
? ?
? 然後我們看回這題
?? 有個奇奇怪怪的條件:$b^2< = d<(b+1)^2 $,這個條件說明什麽呢?會發現因為這個條件所以\(0>=\frac{b-\sqrt d}{2}>-0.5\)
?? 但是我們要求的是\(\lfloor(\frac{b+\sqrt d}{2})^n\rfloor\),那麽這個時候我們會發現。。其實我們把這個式子稍微變一下變成:
?? 就好了
?? 為什麽變成這樣呢?首先前面那個東西,我們會發現其實就是。。用特征方程中有相異兩根求出的通項式的類似形式,所以我們只要令這兩個根為\((\lfloor \frac{b+\sqrt d}{2}\rfloor)^n\)和\((\lfloor \frac{b-\sqrt d}{2}\rfloor)^n\)就好了,然後\(A\)和\(B\)這兩個系數要為\(1\),這樣我們就可以求出\(x_1\)
\[ \begin{aligned} p&=\frac{b+\sqrt d}{2}&&q=\frac{b-\sqrt d}{2}\x_1&=p+q&&x_2=p^2+q^2\a_1&=b&&a_2=\frac{b^2-d}{4} \end{aligned} \]
?? 然後!因為題目的條件:?b mod 2=1,d mod 4=1 ,所以我們發現\(a_1\)和\(a_2\)都是整數,\(x_1\)和\(x_2\)也都是整數,所以!前半部分的答案一定是一個整數(然而其實好像可以直接用一個叫做共軛根式的東西說明但是我不太會那個東西qwq)
? 然後這個時候如果是要求那個式子的下取整的話我們直接判斷一下\(\frac{b-\sqrt d}{2}\)是否大於等於\(1\)即可,會發現只有在\(n\)是偶數並且\(b^2\neq d\)的情況下減去這個部分會導致整體的下取整少一,特判一下就好了
?? 至於前半部分直接矩陣快速冪求出\(x_n\)即可
?? 然後最後還有一個小問題,就是。。這個模數有點令人難受
? 這個時候我們需要。。一個小技巧來處理一下加法和乘法:加法的話直接就先減去一個模數然後如果小於\(0\)再加上模數,乘法的話就像快速冪一樣處理就好了
?
? 代碼大概長這個樣子
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const ll MOD=7528443412579576937;
ll add(ll x,ll y){
ll tmp=-MOD+x+y;
if (tmp<0) tmp+=MOD;
return tmp;
}
ll mul(ll x,ll y){
ll ret=0;
for (;y;y>>=1,x=add(x,x))
if (y&1) ret=add(ret,x);
return ret;
}
struct Mtrix{/*{{{*/
ll a[2][2];
void init(){memset(a,0,sizeof(a));}
void setUnit(){for (int i=0;i<2;++i) for (int j=0;j<2;++j) a[i][j]=i==j;}
friend Mtrix operator * (Mtrix x,Mtrix y){
Mtrix ret;
for (int i=0;i<2;++i)
for (int j=0;j<2;++j){
ret.a[i][j]=0;
for (int k=0;k<2;++k)
ret.a[i][j]=add(ret.a[i][j],mul(x.a[i][k],y.a[k][j]));
}
return ret;
}
}ori,ret,base,ans;/*}}}*/
ll n,m,Ans,d,b;
void ksm(ll y){
ret.setUnit(); base=ori;
for (;y;y>>=1,base=base*base)
if (y&1) ret=ret*base;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
scanf("%lld%lld%lld\n",&b,&d,&n);
if (n==0){printf("1\n");return 0;}
ori.init();
ori.a[1][1]=b;ori.a[0][1]=-(b*b-d)/4;
ori.a[1][0]=1;
ans.init();
ans.a[0][0]=b; ans.a[0][1]=(b*b+d)/2;
if (n>=2)
ksm(n-2),ans=ans*ret;
if (n==1) Ans=ans.a[0][0];
else Ans=ans.a[0][1];
if (b*b!=d&&n%2==0) Ans=add(Ans,MOD-1);
printf("%lld\n",Ans);
}
?
【bzoj4002】有意義的字符串