#include #include #pragma warning(disable:4996) typedef long long ll; const long long MOD = 1000000007; using namespace std; ll mpow(ll x, ll n){ //x^n(mod M) ll ans = 1; while(n != 0){ if(n&1) ans = ans*x % MOD; x = x*x % MOD; n = n >> 1; } return ans; } ll minv(ll x){ return mpow( x, MOD-2 ); } void mtxprd( int p, int q, int r, const ll* A, const ll* B, ll* C ) { int i, j, k; for(i=0; i mtx0(dim*dim); vector mtxtmp(dim*dim); mtxcpy( dim, mtx, &mtx0[0] ); mtxuni( dim, mtx2 ); while(n != 0){ if(n&1) { mtxprd( dim, dim, dim, mtx2, &mtx0[0], &mtxtmp[0] ); mtxcpy( dim, &mtxtmp[0], mtx2 ); } mtxprd( dim, dim, dim, &mtx0[0], &mtx0[0], &mtxtmp[0] ); mtxcpy( dim, &mtxtmp[0], &mtx0[0] ); n = n >> 1; } return; } // <解法> // 求める答えは、(Σa[n])^2 + (Σ(a[n]^2))/2 // この計算は、O(n)ならば簡単に求めることができるが、 // nが大きい場合について解くには何か工夫が必要。 // → 行列累乗を使う // // s[n]=Σ(k=1..n)a[k] を求めるには以下の式を使う // ┌ ┐ ┌ ┐┌ ┐ // │s[n] │ │ 1 p 1 ││s[n-1]│ // │a[n] │=│ 0 p 1 ││a[n-1]│ // │a[n-1]│ │ 0 1 0 ││a[n-2]│ // └ ┘ └ ┘└ ┘ // // s2[n]=Σ(k=1..n)(a[k]^2) を求めるには以下の式を使う // ┌ ┐ ┌ ┐┌ ┐ // │s2[n] │ │ 1 p^2 2p 1 ││s2[n-1] │ // │a[n] *a[n] │=│ 0 p^2 2p 1 ││a[n-1]*a[n-1]│ // │a[n] *a[n-1]│ │ 0 p 1 0 ││a[n-1]*a[n-2]│ // │a[n-1]*a[n-1]│ │ 0 1 0 0 ││a[n-2]*a[n-2]│ // └ ┘ └ ┘└ ┘ // int main(int argc, char* argv[]) { int n,p; scanf("%d%d", &n, &p); if(n==1) { printf("0\n"); return 0; } ll ans0, ans1; { ll a[3*3] = {1, p, 1, 0, p, 1, 0, 1, 0}; ll x0[3] = {1, 1, 0}; ll an[3*3]; mtxpow( 3, a, n-2, an ); ll x1[3]; mtxprd( 3, 3, 1, an, x0, x1 ); ans0 = x1[0]; } { ll a[4*4] = {1, (ll)p*p%MOD, (ll)p*2%MOD, 1, 0, (ll)p*p%MOD, p*2%MOD, 1, 0, p, 1, 0, 0, 1, 0, 0}; ll x0[4] = {1, 1, 0, 0}; ll an[4*4]; mtxpow( 4, a, n-2, an ); ll x1[4]; mtxprd( 4, 4, 1, an, x0, x1 ); ans1 = x1[0]; } ll ans = (ans0*ans0 + ans1)%MOD * minv(2) %MOD; printf("%lld\n", ans); return 0; }