目录
一.题目
二.题解
这道题的难点在于找到递推公式。
我们定义长度为i,珍珠种数为j的项链搭配方法总数为
可以得到一个递推公式:
解释:
先解释前一部分:
就代表已经选了j-1颗珍珠,要在其他的[k-(j-1)]中任选一颗来填充i位置,就有[k-(j-1)]种选法。
后一部分:
就代表在已选的j颗珍珠选一颗来填充第i个位置,就有j种的选法。
好,那么再把它简化成一维。大家会发现第一位永远是i-1,可以直接省去,就变成了:
矩阵就十分好构造了:
三.参考代码
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define mod 1234567891
#define LL long long
int T, n, k;
inline void Read (int &x){
int f = 1; x = 0; char c = getchar ();
while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar ();}
while (c >= '0' && c <= '9') {x = x * 10 + c - 48; c = getchar ();}
x *= f;
}
struct node {
LL r, c, jz[35][35];
node operator * (const node& rhs) const{
node ans;
ans.r = r, ans.c = rhs.c;
for (register int i = 0; i <= ans.r; i ++)
for (register int j = 0; j <= ans.c; j ++)
ans.jz[i][j] = 0;
for (register int i = 1; i <= r; i ++)
for (register int j = 1; j <= rhs.c; j ++)
for (register int k = 1; k <= c; k ++)
ans.jz[i][j] = (ans.jz[i][j] + jz[i][k] * rhs.jz[k][j] % mod) % mod;
return ans;
}
}A, B, C;
inline node qkpow (node x, LL y){
node ans;
ans.r = ans.c = k + 1;
for (register int i = 1; i <= ans.r; i ++)
for (register int j = 1; j <= ans.c; j ++)
if (i != j)
ans.jz[i][j] = 0;
else
ans.jz[i][j] = 1;
while (y > 0){
if (y % 2 == 1)
ans = ans * x;
x = x * x;
y /= 2;
}
return ans;
}
int main (){
Read (T);
while (T --){
Read (n), Read (k);
memset (A.jz, 0, sizeof A.jz);
memset (B.jz, 0, sizeof B.jz);
memset (C.jz, 0, sizeof C.jz);
A.r = A.c = k + 1;
A.jz[1][1] = A.jz[1][k + 1] = A.jz[2][2] = 1;
for (register int i = 3; i <= k + 1; i ++){
A.jz[i][i] = i - 1;
A.jz[i][i - 1] = k - i + 2;
}
B.r = k + 1, B.c = 1;
B.jz[1][1] = 0, B.jz[2][1] = k;
C = qkpow (A, n) * B;
printf ("%lld\n", C.jz[1][1]);
}
return 0;
}