Matrix Multiplication (& Quick Power)
Description
有个高富帅,要送个很装逼的吊坠给他女朋友。
他有k种珠子,然后要串成一个 珠子个数小于等于n 的链子。
因为要够装逼,所以这k种珠子都必须要用到。
好了,输入n和k。
输出他可以做出多少种不一样的项链。
Type
Matrix Multiplication
Quick Power
Analysis
一看又是爽歪歪的递推题。
我们来考虑如何递推出。
设f(x, y)为前x个位置,搞了y种不同的珠子。
然后我们考虑f(x, y)和f(x – 1, ...)关系。
而前后的关系,就差在第x个位置,要放什么类型的珠子。
我们可以放前面x – 1个位置已经放过的珠子,有y种颜色可以选。
那么就有 f(x – 1, y) * y种。
也可以放前面x – 1个位置还没放过的珠子,有k- (y – 1)种颜色可以选。
那么就有 f(x – 1, y – 1) * (k – y + 1) 种。
所以我们就得到递推公式 —— f(x, y) = f(x – 1, y) * y + f(x – 1, y – 1) * (k – y + 1)
好了,有了递推公式就碉堡了,剩下的就是矩阵乘法和快速幂。
当然,也要注意一些小的细节。
我们所求的不是f(x, y),而是f(1, y) ~ f(x, y)的总和(因为珠子个数是小于等于n嘛)。
因此我们需要在矩阵的解向量中,增加一项sum(x – 1),且 sum(x – 1) = sum(x – 2) + f(x - 1, y)。
这题对1234567891取余,有点那啥。
在矩阵乘法中,我们通常是每一个矩阵元素计算完后,再去取余,这样可以减少大量运算时间
(如果你不是这样的,那我告诉你,真的省很多)。
而这题由于这个除数真TMD的大,矩阵相乘的时候,两个元素相乘然后加加加加加...
最后你懂的,就超过long long的范围,溢出了,囧。
深一步讲,因为long long = int * int,而除数过于接近int。
导致我们计算的数接近于int * int * order(矩阵的阶),就爆了。
好吧,怎么办?
一种办法是用unsigned long long,的确可以A,速度还蛮快。
当然如果感觉不够妥妥的,可以每次在计算的时候,做完int * int马上mod,就不会悲剧啦。
(如果你现在不知道我在讲什么,那就等到你在写矩阵相乘函数的时候,你就懂了~)
// HDOJ 2294
// pendant
// by A Code Rabbit
#include <cstdio>
#include <cstring>
const int MAXO = 33;
const int MOD = 1234567891;
template <typename T>
struct Matrix {
T e[MAXO][MAXO];
int o;
Matrix(int ord) { memset(e, 0, sizeof(e)); o = ord; }
Matrix operator*(const Matrix& one) {
Matrix res(o);
for (int i = 0; i < o; i++)
for (int j = 0; j < o; j++)
for (int k = 0; k < o; k++)
res.e[i][j] += e[i][k] * one.e[k][j];
return res;
}
Matrix operator%(int mod) {
for (int i = 0; i < o; i++)
for (int j = 0; j < o; j++)
e[i][j] %= mod;
return *this;
}
};
template <typename T>
T QuickPower(T rdx, int exp, int mod) {
T res = rdx;
exp--;
while (exp) {
if (exp & 1) res = res * rdx % mod;
exp >>= 1;
rdx = rdx * rdx % mod;
}
return res;
}
int n, k;
int main() {
int tot_case;
scanf("%d", &tot_case);
while (tot_case--) {
// Input.
scanf("%d%d", &n, &k);
// Sovle.
Matrix<unsigned long long> mat_one(k + 1);
mat_one.e[0][0] = 1;
mat_one.e[k][0] = 1;
for (int i = 1; i < k + 1; ++i) {
mat_one.e[i][i] = i;
if (i > 1) mat_one.e[i - 1][i] = k - i + 1;
}
Matrix<unsigned long long> mat_ans = QuickPower(mat_one, n, MOD);
// Output.
printf("%d\n", k * mat_ans.e[1][0] % MOD);
}
return 0;
}