HDU 2254 奥运 Matrix Power
如果 a 到 b 有路,则map[a][b] = 1,否则map[a][b] = 0,譬如如果1→3,1→4,2→1,2→3,3→4,4→2,4→3有路,则可以构造矩阵:
矩阵的k次方表示这个矩阵走了k步。
所以k天后就算矩阵的k次方。
这样就变成:初始矩阵的^[t1,t2]这个区间内的v[v1][v2]的和。
所以就是二分等比序列求和上场的时候了。
跟HDU 1588 Gauss Fibonacci的算法一样。
Also check http://alanyume.com/97.html
Please read full article from HDU 2254 奥运 Matrix Power
Problem Description
北京迎来了第一个奥运会,我们的欢呼声响彻中国大地,所以今年的奥运金牌 day day up!
比尔盖兹坐上鸟巢里,手里摇着小纸扇,看的不亦乐乎,被俺们健儿的顽强拼搏的精神深深的感动了。反正我的钱也多的没地方放了,他对自己说,我自己也来举办一个奥运会,看谁的更火。不过他的奥运会很特别:
1 参加人员必须是中国人;
2 至少会加法运算(因为要计算本人获得的金牌数)
他知道中国有很多的名胜古迹,他知道自己在t1 到 t2天内不可能把所有的地方都玩遍,所以他决定指定两个地方v1,v2,如果参赛员能计算出在t1到t2天(包括t1,t2)内从v1到v2共有多少种走法(每条道路走需要花一天的时间,且不能在某个城市停留,且t1=0时的走法数为0),那么他就会获得相应数量的金牌,城市的总数<=30,两个城市间可以有多条道路
,每条都视为是不同的。
比尔盖兹坐上鸟巢里,手里摇着小纸扇,看的不亦乐乎,被俺们健儿的顽强拼搏的精神深深的感动了。反正我的钱也多的没地方放了,他对自己说,我自己也来举办一个奥运会,看谁的更火。不过他的奥运会很特别:
1 参加人员必须是中国人;
2 至少会加法运算(因为要计算本人获得的金牌数)
他知道中国有很多的名胜古迹,他知道自己在t1 到 t2天内不可能把所有的地方都玩遍,所以他决定指定两个地方v1,v2,如果参赛员能计算出在t1到t2天(包括t1,t2)内从v1到v2共有多少种走法(每条道路走需要花一天的时间,且不能在某个城市停留,且t1=0时的走法数为0),那么他就会获得相应数量的金牌,城市的总数<=30,两个城市间可以有多条道路
,每条都视为是不同的。
Input
本题多个case,每个case:
输入一个数字n表示有n条道路 0<n<10000
接下来n行每行读入两个数字 p1,p2 表示城市p1到p2有道路,并不表示p2到p1有道路 (0<=p1,p2<2^32)
输入一个数字k表示有k个参赛人员
接下来k行,每行读入四个数据v1,v2,t1,t2 (0<=t1,t2<10000)
输入一个数字n表示有n条道路 0<n<10000
接下来n行每行读入两个数字 p1,p2 表示城市p1到p2有道路,并不表示p2到p1有道路 (0<=p1,p2<2^32)
输入一个数字k表示有k个参赛人员
接下来k行,每行读入四个数据v1,v2,t1,t2 (0<=t1,t2<10000)
Output
对于每组数据中的每个参赛人员输出一个整数表示他获得的金牌数(mod 2008)
Sample Input
6 1 2 1 3 2 3 3 2 3 1 2 1 3 1 2 0 0 1 2 1 100 4 8 3 50
Sample Output
0 1506 0
这样构造好矩阵之后,如果求从 1 到 2 走 5 天(每条路走一天),有几条路,就可以这样计算:
结果中,第 n 行第 m 列就是 n 到 m 要走 5 天的路数。
一张有向图的邻接矩阵A,A表示所有点之间路径长度为一的路径数量,A^n则表示路径长度为n的路径数量,故需要求某两点在(A^t1)~(A^t2)的路径数量之和矩阵的k次方表示这个矩阵走了k步。
所以k天后就算矩阵的k次方。
这样就变成:初始矩阵的^[t1,t2]这个区间内的v[v1][v2]的和。
所以就是二分等比序列求和上场的时候了。
跟HDU 1588 Gauss Fibonacci的算法一样。
struct
Matrix {
int
mat[N][N];
int
n, m;
Matrix() {
//初始化
n = m = N;
memset
(mat, 0,
sizeof
(mat));
}
inline
void
init(
int
row,
int
column) {
//初始矩阵大小
n = row, m = column;
}
void
init_e() {
//单位矩阵
for
(
int
i = 0; i < n; i++) {
for
(
int
j = 0; j < m; j++) {
mat[i][j] = (i == j);
}
}
}
};
//加法
Matrix operator + (Matrix a, Matrix b) {
Matrix ret;
ret.init(a.n, a.m);
for
(
int
i = 0; i < a.n; i++) {
for
(
int
j = 0; j < a.m; j++) {
ret.mat[i][j] = a.mat[i][j] + b.mat[i][j];
if
(ret.mat[i][j] >= mod) {
ret.mat[i][j] %= mod;
}
}
}
return
ret;
}
//n行m列 * m行p列 = n行p列
Matrix operator * (Matrix a, Matrix b) {
Matrix ret;
ret.init(a.n, b.m);
for
(
int
i = 0; i < a.n; i++) {
for
(
int
k = 0; k < a.m; k++)
if
(a.mat[i][k]) {
for
(
int
j = 0; j < b.m; j++)
if
(b.mat[k][j]) {
ret.mat[i][j] = ret.mat[i][j] + a.mat[i][k] * b.mat[k][j];
if
(ret.mat[i][j] >= mod) {
ret.mat[i][j] %= mod;
}
//if
}
//for(j)
}
//for(k)
}
//for(i)
return
ret;
}
//求幂一般都是正方形矩阵,所以ret = a;
Matrix operator ^ (Matrix a,
int
b) {
Matrix ret = a, tmp = a;
ret.init_e();
for
( ; b; b >>= 1) {
if
(b & 1) {
ret = ret * tmp;
}
tmp = tmp * tmp;
}
return
ret;
}
//递归幂求和
//用二分法求矩阵和,递归实现
Matrix Power_Sum1(Matrix a,
int
b) {
Matrix ret = a;
ret.init_e();
if
(b == 1) {
return
a;
}
else
if
(b & 1) {
return
(a ^ b) + Power_Sum1(a, b - 1);
}
else
{
return
Power_Sum1(a, b >> 1) * ((a ^ (b >> 1)) + ret);
}
}
//非递归幂求和
Matrix Power_Sum2(Matrix a,
int
b) {
int
k = 0 ,ss[32];
Matrix tp1, tp2, ret;
tp1 = tp2 = ret = a;
ret.init_e();
while
(b) {
ss[k++] = b & 1;
b >>= 1;
}
for
(
int
i = k - 2; i >= 0; i--) {
tp1 = tp1 * (tp2 + ret);
tp2 = tp2 * tp2;
if
(ss[i]) {
tp2 = tp2 * a;
tp1 = tp1 + tp2;
}
}
return
tp1;
}
int
main(
void
) {
int
cas, n;
int
v1, v2, t1, t2, x, y;
while
(~
scanf
(
"%d"
, &cas)) {
map <
int
,
int
> mp;
//最多只有30条路,所以用map映射
mp.clear();
Matrix a, b, c;
int
cnt = 1;
for
(
int
i = 0; i < cas; i++) {
scanf
(
"%d %d"
, &x, &y);
if
(!mp[x]) {
mp[x] = cnt++;
}
if
(!mp[y]) {
mp[y] = cnt++;
}
a.mat[mp[x]][mp[y]] ++;
}
a.init(cnt, cnt);
// a.print();
b.init(cnt, cnt);
c.init(cnt, cnt);
scanf
(
"%d"
, &n);
while
(n--) {
scanf
(
"%d%d%d%d"
, &v1, &v2, &t1, &t2);
x = mp[v1];
y = mp[v2];
if
(x == 0 || y == 0 || (t1 == 0 && t2 == 0)) {
puts
(
"0"
);
continue
;
}
int
sum;
if
(t1 <= 1) {
b = Power_Sum2(a, t2);
// b.print();
sum = b.mat[x][y] % mod;
printf
(
"%d\n"
,sum);
continue
;
}
b = Power_Sum2(a, t2);
c = Power_Sum2(a, t1 - 1);
sum = (b.mat[x][y] % mod - c.mat[x][y] % mod + mod) % mod;
printf
(
"%d\n"
, sum);
}
//while(n)
}
//while(cas)
return
0;
}
Please read full article from HDU 2254 奥运 Matrix Power