題面node
這個題暴好啊,考了不少東西。c++
首先設f(x)爲離終點還有x步要走的指望步數,咱們能夠發現 :ui
1.x>=k時,x能夠轉移到的點的下標都<x。spa
2.x<k時,則可能走回到x或者下標更大的點。blog
由於k特別小,因此咱們能夠把 f(0) (顯然是0),f(1),f(2),.....,f(k-1) 暴力高斯消元出來 (這個大家不會的話能夠試着把每一個0<x<k的x的等式寫出來,而後把f(x)項全移到左邊,其餘項全移到右邊,就能夠獲得一個方程;這樣能夠列k-1個方程,正好k-1個未知數,高斯消元模板)。get
這樣咱們就解決了2.狀況。因而對於大量1.狀況,咱們即可以用2.狀況推的下標比較小的f() 作矩陣乘法。it
因此這就是兩個題:先建一個矩陣而後高斯消元,再建一個而後矩陣快速冪,最後再作一次向量乘矩陣就能夠獲得答案了。模板
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=23,ha=1000000007; inline int add(int x,int y){ x+=y; return x>=ha?x-ha:x;} inline void ADD(int &x,int y){ x+=y; if(x>=ha) x-=ha;} inline int ksm(int x,int y){ int an=1; for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha; return an; } int k,inv,Inv,ans; ll n; struct node{ int a[N][N]; inline void clear(){ memset(a,0,sizeof(a));} inline void Base(){ clear(); for(int i=0;i<=k;i++) a[i][i]=1; } node operator *(const node &u)const{ node r; r.clear(); for(int l=0;l<=k;l++) for(int i=0;i<=k;i++) for(int j=0;j<=k;j++) ADD(r.a[i][j],a[i][l]*(ll)u.a[l][j]%ha); return r; } inline void build(){ clear(),a[k][k]=1; for(int i=1;i<k;i++){ a[i][k]=(i*2>k)?1:k*(ll)Inv%ha,a[i][i]=1; for(int j=1,to;j<=k;j++){ to=i-j; if(to<0) to=-to; if(to&&to!=i) ADD(a[i][to],ha-((i*2>k)?inv:Inv)); } } } inline void solve(){ for(int i=1,ne;i<k;i++){ for(int j=i;j<k;j++) if(a[j][i]){ ne=j; break;} if(ne!=i) for(int l=i;l<=k;l++) swap(a[ne][l],a[i][l]); int ni=ksm(a[i][i],ha-2),now; for(int j=i+1;j<k;j++){ now=ni*(ll)a[j][i]%ha; for(int l=i;l<=k;l++) ADD(a[j][l],ha-a[i][l]*(ll)now%ha); } } for(int i=k-1;i;i--){ for(int j=i+1;j<k;j++) ADD(a[i][k],ha-a[i][j]*(ll)a[j][k]%ha); a[i][k]=a[i][k]*(ll)ksm(a[i][i],ha-2)%ha; // printf("%d %d\n",i,a[i][k]); } } inline void init(){ clear(); for(int i=k-2;i>=0;i--) a[i+1][i]=1; for(int i=0;i<k;i++) a[i][k-1]=inv; a[k][k-1]=1,a[k][k]=1; } }A,X,ANS; int main(){ scanf("%lld%d",&n,&k),inv=ksm(k,ha-2),Inv=ksm(k-1,ha-2); if(k==1){ printf("%d\n",n%ha); return 0;} A.build(),A.solve(),X.init(); n-=k-1,ANS.Base(); for(;n;n>>=1,X=X*X) if(n&1) ANS=ANS*X; for(int i=0;i<=k;i++) ADD(ans,A.a[i][k]*(ll)ANS.a[i][k-1]%ha); printf("%d\n",ans); return 0; }