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;
}
posted @ 2020-02-28 17:02  Mrzdtz220  阅读(67)  评论(0编辑  收藏  举报