题意:有个高富帅,要送个很装逼的吊坠给他女朋友。他有k种珠子,然后要串成一个珠子个数小于等于n 的链子(k种珠子都必须要用到)。输入n和k,输出他可以做出多少种不一样的项链。
思路:可以想到递推式f(x, y) = f(x – 1, y) * y + f(x – 1, y – 1) * (k – y + 1)(表示x个珠子用了y种类型),因为n过大,无法直接求出来,所以要使用矩阵快速幂。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MOD = 1234567891;
const int MAXN = 35;
struct mat{
ll s[MAXN][MAXN];
mat() {
memset(s, 0, sizeof(s));
}
mat operator * (const mat& c) {
mat ans;
memset(ans.s, 0, sizeof(ans.s));
for (int i = 0; i < MAXN; i++)
for (int j = 0; j < MAXN; j++)
for (int k = 0; k < MAXN; k++)
ans.s[i][j] = (ans.s[i][j] + s[i][k] * c.s[k][j]) % MOD;
return ans;
}
void put() {
for (int i = 0; i < MAXN; i++) {
for (int j = 0; j < MAXN; j++)
printf("%lld ", s[i][j]);
printf("\n");
}
}
}c;
ll n;
int k;
void init() {
memset(c.s, 0, sizeof(c.s));
c.s[0][0] = 1;
c.s[k][0] = 1;
for (int i = 1; i < k + 1; i++) {
c.s[i][i] = i;
if (i > 1)
c.s[i - 1][i] = k - i + 1;
}
}
mat pow_mod(ll n) {
if (n == 1)
return c;
mat a = pow_mod(n / 2);
mat ans = a * a;
if (n % 2)
ans = ans * c;
return ans;
}
int main() {
int cas;
scanf("%d", &cas);
while (cas--) {
scanf("%lld%d", &n, &k);
init();
mat ans = pow_mod(n);
printf("%lld\n", k * ans.s[1][0] % MOD);
}
return 0;
}