[玲珑学院 1031 Bob and Alice are eating food]DP+矩阵快速幂
题目链接:[玲珑学院 1031 Bob and Alice are eating food]
题意描述:有apples,pears,peaches,bananas, oranges and lemons.六种水果。每种水果数量可以看成无限多。吃K个水果,要保证吃的apples,pears 是偶数(0也算是偶数),求方案数模
1e9+7
。
解题思路:表示官方题解母函数+泰勒展开看不懂。问了一下凯神和qwb,才明白了DP+矩阵快速幂的做法。主要还是对状态的理解,对K进行状态转移,可以只去考虑apple和pear。
用
i,j(0≤i,j≤1)
分别表示apple,pear的奇偶性,
0
表示偶数,
那么,就可以用
A00,A01,A10,A11
表示所有的状态。
列出状态转移方程如下:
A00=4∗A00+A01+A10;A01=4∗A01+A00+A11;A10=4∗A10+A01+A11;A11=4∗A11+A01+A10;
然后,就可以构造初始矩阵和转移矩阵了。
感觉自己往往很多题目都很难想到矩阵快速幂啊。引用一下凯神的心得。
先写方程,如果发现转移的时候是一种线性的转移,那么就可以尝试构造转移矩阵了。比如这个题,你把状态转移方程写出来,发现就是几个状态之间的线性变换,那么就可以写成矩阵的形式了
#include <queue>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w",stdout)
#define fst first
#define snd second
typedef long long LL;
typedef vector<LL> Vec;
typedef vector<Vec> Mat;
const LL MOD = 1e9 + 7;
LL T, K;
Mat mat_mul(Mat a, Mat b) {
Mat ret(4, Vec(4, 0));
int ra = a.size(), rb = b.size(), t = a[0].size();
for (int k = 0; k < t; k++) {
for (int i = 0; i < ra; i++) {
for (int j = 0; j < rb; j++) {
ret[i][j] = (ret[i][j] + a[i][k] * b[k][j]) % MOD;
}
}
}
return ret;
}
Mat mat_pow(Mat a, LL b) {
Mat ret(4, Vec(4, 0));
for (int i = 0; i < ret.size(); i++) {
ret[i][i] = 1;
}
while(b > 0) {
if(b & 1LL) ret = mat_mul(ret, a);
a = mat_mul(a, a);
b >>= 1;
}
return ret;
}
void mat_assign(Mat& a, LL ar[][4]) {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
a[i][j] = ar[i][j];
}
}
}
int main() {
#ifndef ONLINE_JUDGE
// FIN;
#endif // ONLINE_JUDGE
LL cas = 0;
LL m1[4][4] = {
{4, 1, 1, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0}
};
LL m2[4][4] = {
{4, 1, 1, 0},
{1, 4, 0, 1},
{1, 0, 4, 1},
{0, 1, 1, 4}
};
Mat init(4, Vec(4));
Mat tras(4, Vec(4));
mat_assign(init, m1);
mat_assign(tras, m2);
Mat res(4, Vec(4));
scanf("%lld", &T);
while(T --) {
scanf("%lld", &K);
res = mat_pow(tras, K - 1);
res = mat_mul(init, res);
printf("Case #%lld: %lld\n", ++cas, res[0][0]);
}
return 0;
}