BZOJ 5015: [Snoi2017]礼物

\(f_i\) 为答案,\(s_i\) 为前缀和
那么 \(s_i = 2s_{i-1}+i^k\)
这个根据二项式系数可以矩阵快速幂

#include <bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define pii pair<int, int>
#define lp p << 1
#define rp p << 1 | 1
#define mid ((l + r) >> 1)
#define ll long long
#define db double
#define rep(i,a,b) for(int i=a;i<b;i++)
#define per(i,a,b) for(int i=b-1;i>=a;i--)
#define Edg int ccnt=1,head[N],to[N*2],ne[N*2];void addd(int u,int v){to[++ccnt]=v;ne[ccnt]=head[u];head[u]=ccnt;}void add(int u,int v){addd(u,v);addd(v,u);}
#define Edgc int ccnt=1,head[N],to[N*2],ne[N*2],c[N*2];void addd(int u,int v,int w){to[++ccnt]=v;ne[ccnt]=head[u];c[ccnt]=w;head[u]=ccnt;}void add(int u,int v,int w){addd(u,v,w);addd(v,u,w);}
#define es(u,i,v) for(int i=head[u],v=to[i];i;i=ne[i],v=to[i])
const int MOD = 1e9 + 7;
void M(int &x) {if (x >= MOD)x -= MOD; if (x < 0)x += MOD;}
int qp(int a, int b = MOD - 2) {int ans = 1; for (; b; a = 1LL * a * a % MOD, b >>= 1)if (b & 1)ans = 1LL * ans * a % MOD; return ans % MOD;}
int gcd(int a, int b) { while (b) { a %= b; std::swap(a, b); } return a; }

const int N = 15;
int n;
ll m;

struct Mat {
    int mat[N][N];
    Mat() { memset(mat, 0, sizeof(mat)); }
    Mat operator * (const Mat &p) const {
        Mat c;
        rep (i, 1, n +3) {
            rep (j, 1, n + 3) {
                ll temp = 0;
                rep (k, 1, n + 3) {
                    temp += 1LL * mat[i][k] * p.mat[k][j];
                    if (temp >= (1LL << 60)) temp %= MOD;
                }
                c.mat[i][j] = temp % MOD;
            }
        }
        return c;
    }
} base;

Mat qp(Mat a, ll b) {
    Mat c;
    rep (i, 1, n + 1) c.mat[i][i] = 1;
    while (b) {
        if (b & 1) c = a * c;
        a = a * a;
        b >>= 1;
    }
    return c;
}

int C[N][N];

int main() {
    C[0][0] = 1;
    rep (i, 1, N) {
        C[i][0] = C[i][i] = 1;
        rep (j, 1, i) M(C[i][j] = C[i - 1][j] + C[i - 1][j - 1]);
    }
    scanf("%lld%d", &m, &n);
    Mat base;
    base.mat[1][1] = 2;
    rep (j, 2, n + 3) base.mat[j][1] = C[n][j - 2];
    rep (j, 2, n + 3) {
        int cnt = 0;
        rep (i, j, n + 3) {
            base.mat[i][j]= C[n - j + 2][cnt++];
        }
    }
    Mat res = qp(base, m - 2);
    int ans = 0;
    rep (i, 1, n + 3)
        M(ans += res.mat[i][1]);
    res = base * res;
    int ans2 = 0;
    rep (i, 1, n + 3) 
        M(ans2 += res.mat[i][1]);
    M(ans2 = ans2 - ans);
    printf("%d\n", ans2);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Mrzdtz220/p/12377969.html