题意
热情好客的请森林中的朋友们吃饭,他的朋友被编号为 1~N,每个到来的朋友都会带给他一些礼物:。其中,第一个朋友会带给他 1 个,之后,每一个朋友到来以后,都会带给他之前所有人带来的礼物个数再加他的编号的 K 次方那么多个。所以,假设 K=2,前几位朋友带来的礼物个数分别是:1,5,15,37,83假设 K=3,前几位朋友带来的礼物个数分别是:1,9,37,111现在,好奇自己到底能收到第 N 个朋友多少礼物,因此拜托于你了。已知 N,K请输出第 N 个朋
友送的礼物个数 mod1000000007。
N≤
1018
,K≤10
题解
这题的话,n为
1018
,然后还一副递推式很显然的样子,一看就是矩阵乘法
递推式的话也是很显然的,设前i个人的答案总和
fi
fi=2∗fi−1+ik2
然后答案就是
fn−fn−1
然后难点就是
ik
怎么矩乘维护
明显地,直接弄是弄不出来的,你需要
(i−1)k−1
,
(i−1)k−2
等等
然后你知道了这些之后,其实合并的话,就是杨辉三角
因为你就相当于一个
(n+1)k
形式而已,拆开之后,各项的系数就是杨辉三角了
然后矩乘搞一搞就好了
CODE:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long LL;
const int MOD=1000000007;
const LL N=25;
LL n,k;
LL C[N][N];
struct qq{LL s[20][20];};
qq operator * (qq a,qq b)
{
qq c;
for (LL u=0;u<=k+1;u++)
for (LL i=0;i<=k+1;i++)
{
c.s[u][i]=0;
for (LL j=0;j<=k+1;j++)
c.s[u][i]=(c.s[u][i]+a.s[u][j]*b.s[j][i]%MOD)%MOD;
}
return c;
}
qq a,b,c,d,e;
qq pow (qq x,LL y)
{
if (y==0) return e;
if (y==1) return x;
qq lalal=pow(x,y>>1);
lalal=lalal*lalal;
if (y&1) lalal=lalal*x;
return lalal;
}
int main()
{
scanf("%lld%lld",&n,&k);
C[0][0]=1;
for (LL u=1;u<=k;u++)
{
C[u][0]=1;
for (LL i=1;i<=u;i++) C[u][i]=(C[u-1][i]+C[u-1][i-1])%MOD;
}
a.s[k+1][k]=1;a.s[k+1][k+1]=2;
for (LL u=0;u<=k;u++)
{
b.s[u][0]=1;
e.s[u][u]=1;
for (LL i=0;i<=u;i++) a.s[u][i]=C[u][i];
}
e.s[k+1][k+1]=1;
c=pow(a,n);d=pow(a,n-1);
c=c*b;d=d*b;
printf("%lld\n",((c.s[k+1][0]-d.s[k+1][0])%MOD+MOD)%MOD);
return 0;
}