码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj5015: [Snoi2017]礼物

时间:2018-03-13 23:53:44      阅读:225      评论:0      收藏:0      [点我收藏+]

标签:std   现在   矩阵   int   printf   带来   森林   clu   a*   

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

题解

记第\(n\)个朋友送的礼物数为\(a_n\),前\(n\)个朋友送的礼物数之和为\(s_n\),那么显然有\(s_n=2\times s_{n-1}+n^k\)\(a_n=s_n-s_{n-1}\)
由于题目中\(N\)很大,直接递推显然会超时,考虑用矩阵快速幂加速。

注意到\(n^k\)这一项与\(n\)有关,因此我们在转移时要顺带考虑这一项如何转移。根据二项式定理\[(n+1)^k=\sum_{i=0}^kC_k^i\times n^{k-i}\]我们只要知道了\(n^0\),\(n^1\),...,\(n^k\),就可以算出\((n+1)^0\),\((n+1)^1\),...,\((n+1)^k\).那么我们可以让\(n^0\),\(n^1\),...,\(n^k\)随矩阵一同转移。
首先设计向量\[\vec f_n=\begin{pmatrix}s_n\\ n^0\\ n^1\\ ...\\ n^k\\\end{pmatrix}\]经过一次转移,我们希望得到\[\vec f_{n+1}=\begin{pmatrix}s_n\\ n^0\\ n^1\\ ...\\ n^k\\\end{pmatrix}\]我们需要设计一个矩阵\(A\)使得\[A\vec f_n=\vec f_{n+1}\]由之前推出的结论,我们可以得到\[A=\begin{bmatrix}2 & C_k^k & C_k^{k-1} & ... & C_k^0 \\ 0 & C_0^0 & 0 & ... & 0\\ 0 & C_1^1 & C_1^0 & ... & 0\\ ... & ... & ... & ... & ...\\ 0 & C_k^k & C_k^{k-1} & ... & C_k^0\end{bmatrix}\]

代码

#include<bits/stdc++.h>
#define MAXN 15
#define P 1000000007
#define LL long long
using namespace std;
struct Mat{
    LL a[MAXN][MAXN];
    int n;
    void Init(){for(int i=1;i<=n;i++)a[i][i]=1;}
    Mat(){memset(a,0,sizeof(a));}
}A,B,C;
struct Vec{
    LL a[MAXN];
    int n;
    Vec(){memset(a,0,sizeof(a));}
}f,g;
inline Mat operator * (Mat &x,Mat &y){
    Mat z;z.n=x.n;
    for(int i=1;i<=x.n;i++){
        for(int j=1;j<=x.n;j++){
            for(int k=1;k<=x.n;k++){
                z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j]%P)%P;
            }
        }
    }
    return z;
}
inline Vec operator * (Mat &x,Vec &y){
    Vec z;z.n=x.n;
    for(int i=1;i<=x.n;i++){
        for(int k=1;k<=x.n;k++){
            z.a[i]=(z.a[i]+x.a[i][k]*y.a[k]%P)%P;
        }
    }
    return z;
}
inline Mat qp(Mat x,LL y){
    Mat z;z.n=x.n;z.Init();
    while(y){
        if(y&1)z=x*z;
        x=x*x;y>>=1;
    }
    return z;
} 
LL N;
int K;
int main(){
    scanf("%lld%d",&N,&K);
    f.a[1]=1;f.n=K+2;
    for(int i=2;i<=K+2;i++)f.a[i]=1;
    A.a[2][2]=1;
    for(int i=3;i<=K+2;i++){
        A.a[i][2]=A.a[i][i]=1;
        for(int j=3;j<i;j++){
            A.a[i][j]=(A.a[i-1][j]+A.a[i-1][j-1])%P;
        }
    }
    A.a[1][1]=2;A.n=K+2;
    for(int i=2;i<=K+2;i++)A.a[1][i]=A.a[K+2][i];
    B=qp(A,N-2);
    f=B*f;g=A*f;
    printf("%lld",(g.a[1]-f.a[1]+P)%P);
    return 0; 
}

bzoj5015: [Snoi2017]礼物

标签:std   现在   矩阵   int   printf   带来   森林   clu   a*   

原文地址:https://www.cnblogs.com/lrj998244353/p/8563473.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!