虽然是一道水题 但由于我对这种类型的矩阵过于生疏 还是要写一篇题解巩固一下
直接矩乘吧
数据范围非常之大 完全没有其它想法 一定是和二分有关(当然你也可以背公式)
假设前面的人一共送了
S
S
,那么当前这个人送的就是
当前的和就是
S∗2+i∗i
S
∗
2
+
i
∗
i
因此我们给定一个一维矩阵
[I0,i1,i2,i3......ik,S]
[
I
0
,
i
1
,
i
2
,
i
3
.
.
.
.
.
.
i
k
,
S
]
为什么这样子定矩阵呢??
因为
(i+1)k=C0k∗i01n+C1k∗i112...+Ckkik10
(
i
+
1
)
k
=
C
k
0
∗
i
0
1
n
+
C
k
1
∗
i
1
1
2
.
.
.
+
C
k
k
i
k
1
0
将 1 1 全部忽略 我们就能够得到 从 推 (i+1)k ( i + 1 ) k 的各个项的系数
其中包含了 i1,i2,i3 i 1 , i 2 , i 3 这样的项
所以我们也需要把它们求出来
而对应每一个元素对于这每一项的系数就是如上的组合数
构造出来的系数矩阵
1,C01,C02,C03,C04,C05.... 1 , C 1 0 , C 2 0 , C 3 0 , C 4 0 , C 5 0 . . . .
0,C11,C12,C13,C14,C15.... 0 , C 1 1 , C 2 1 , C 3 1 , C 4 1 , C 5 1 . . . .
0,0,C22,C23,C24,C25.... 0 , 0 , C 2 2 , C 3 2 , C 4 2 , C 5 2 . . . .
........ . . . . . . . .
然后单独取出
S
S
的系数
对于 为
1
1
对于 为
2
2
最后把 相加即为结果
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const long long mod=1e9+7;
int S;
struct mat
{
long long x[123][123];
mat(){memset(x,0,sizeof(x));}
mat operator*(mat &B)const
{
mat C;
for(int a=0;a<S;a++)
for(int b=0;b<S;b++)
for(int mid=0;mid<S;mid++)
C.x[a][b]=(C.x[a][b]+x[a][mid]*B.x[mid][b])%mod;
return C;
}
};
long long C[123][123];
void GetC(int n)
{
C[0][0]=C[1][0]=C[1][1]=1;
for(int i=1;i<=n;i++)
{
C[i][0]=1;
for(int j=1;j<=n;j++)
C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
}
mat KSM(mat A,mat B,long long T)
{
while(T)
{
if(T&1)A=A*B;
T>>=1;
B=B*B;
}
return A;
}
long long N;int K;
mat A,B;
int main()
{
//freopen("In.txt","r",stdin);
scanf("%lld%d",&N,&K);
GetC(K);
for(int i=0;i<=K;i++)
for(int j=0;j<=i;j++)
B.x[j][i]=C[i][j];
S=K+3;
B.x[K][K+1]=B.x[K+2][K+1]=1;
B.x[K][K+2]=1;B.x[K+2][K+2]=2;
//A.x[0][0]=A.x[0][K+1]=1;
for(int i=0;i<=K+1;i++)A.x[0][i]=1;
A=KSM(A,B,N);
printf("%lld",A.x[0][K+1]);
}