zoukankan      html  css  js  c++  java
  • BZOJ_5015_[Snoi2017]礼物_矩阵乘法

    BZOJ_5015_[Snoi2017]礼物_矩阵乘法

    Description

    热情好客的请森林中的朋友们吃饭,他的朋友被编号为 1~N,每个到来的朋友都会带给他一些礼物:。其中,第
    一个朋友会带给他 1 个,之后,每一个朋友到来以后,都会带给他之前所有人带来的礼物个数再加他的编号的 K 
    次方那么多个。所以,假设 K=2,前几位朋友带来的礼物个数分别是:1,5,15,37,83假设 K=3,前几位朋友带来的
    礼物个数分别是:1,9,37,111现在,好奇自己到底能收到第 N 个朋友多少礼物,因此拜托于你了。已知 N,K请输
    出第 N 个朋友送的礼物个数 mod1000000007。

    Input

    第一行,两个整数 N,K
    N≤10^18,K≤10

    Output

    一个整数,表示第 N 个朋友送的礼物个数 mod1000000007。 

    Sample Input

    4 2

    Sample Output

    37

    设序列的前缀和为$S_n$,$S_n=S_{n-1}+n^{k}$。
    $(S_{n-1}; n^{k}; ...n^{0})$ -> $(S_{n};(n+1)^{k};...(n+1)^{0})$
    转移矩阵发现可以用二项式定理。
     
    代码:
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    int m;
    ll n,mod=1000000007,c[15][15];
    struct Mat {
    	ll v[14][14];
    	Mat(){memset(v,0,sizeof(v));}
    	Mat operator*(const Mat &x)const {
    		Mat re;int i,j,k;
    		for(i=1;i<=m;i++) {
    			for(j=1;j<=m;j++) {
    				for(k=1;k<=m;k++) {
    					(re.v[i][j]+=v[i][k]*x.v[k][j]%mod)%=mod;
    				}
    			}
    		}
    		return re;
    	}
    };
    void print(Mat x) {
    	int i,j;
    	for(i=1;i<=m;i++) {
    		for(j=1;j<=m;j++) {
    			printf("%lld ",x.v[i][j]);
    		}
    		puts("");
    	}
    }
    Mat qp(Mat x,ll y) {
    	Mat I;
    	int i;
    	for(i=1;i<=m;i++) I.v[i][i]=1;
    	while(y) {
    		if(y&1ll) I=I*x;
    		x=x*x;
    		y>>=1ll;
    	}
    	return I;
    }
    Mat build() {
    	Mat x;
    	int i,j;
    	x.v[1][1]=2; x.v[2][1]=1;
    	for(i=2;i<=m;i++) {
    		int k=m-i+1;
    		for(j=0;j<=k;j++) {
    			x.v[j+i][i]=c[k-1][j];
    		}
    	}
    	/*for(i=1;i<=m;i++) {
    		for(j=1;j<=m;j++) {
    			printf("%lld ",x.v[i][j]);
    		}
    		puts("");
    	}*/
    	return x;
    }
    void init() {
    	int i,j;
    	for(i=0;i<=m;i++) c[i][0]=c[i][i]=1;
    	for(i=1;i<=m;i++) {
    		for(j=1;j<=m;j++) {
    			c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
    		}
    	}
    }
    int main() {
    	scanf("%lld%d",&n,&m); m+=2;
    	init();
    	Mat A;
    	int i;
    	for(i=2;i<=m;i++) A.v[1][i]=1;
    	Mat x=build();
    	Mat T=A*qp(x,n-1);
    	//print(T);
    	printf("%lld
    ",((T*x).v[1][1]-T.v[1][1]+mod)%mod);
    }
    
  • 相关阅读:
    visual studio 2019 企业版下载
    对IT战略的认识
    投融资,你了解吗?
    一品投资农副产品电商平台工作内容
    高明的决策和投资远比低效的勤奋更重要
    随笔
    思维方式的不同
    公司经营问题探讨
    盘点海口最好吃的西餐厅top10
    羽毛球运动技巧
  • 原文地址:https://www.cnblogs.com/suika/p/8901964.html
Copyright © 2011-2022 走看看