您的位置:首页 > 其它

HDOJ 2294 - Pendant

2012-07-16 15:23 218 查看


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,就不会悲剧啦。

(如果你现在不知道我在讲什么,那就等到你在写矩阵相乘函数的时候,你就懂了~)

Solution

// 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  matrix struct 百度