[原创]HDU 5015 233 Matrix 【矩阵快速幂】

2016-07-29 17:50:50 Tabris_ 阅读数:388


博客爬取于2020-06-14 22:44:03
以下为正文

版权声明:本文为Tabris原创文章,未经博主允许不得私自转载。
https://blog.csdn.net/qq_33184171/article/details/52067386


题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5015

-------------------------------------------.

233 Matrix

Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1817 Accepted Submission(s): 1075

Problem Description
In our daily life we often use 233 to express our feelings. Actually, we may say 2333, 23333, or 233333 … in the same meaning. And here is the question: Suppose we have a matrix called 233 matrix. In the first line, it would be 233, 2333, 23333… (it means a0,1 = 233,a0,2 = 2333,a0,3 = 23333…) Besides, in 233 matrix, we got ai,j = ai-1,j +ai,j-1( i,j ≠ 0). Now you have known a1,0,a2,0,…,an,0, could you tell me an,m in the 233 matrix?

Input
There are multiple test cases. Please process till EOF.

For each case, the first line contains two postive integers n,m(n ≤ 10,m ≤ 109). The second line contains n integers, a1,0,a2,0,…,an,0(0 ≤ ai,0 < 231).

Output
For each case, output an,m mod 10000007.

Sample Input
1 1
1
2 2
0 0
3 7
23 47 16

Sample Output
234
2799
72937

Hint
这里写图片描述

-----------------------------------------------------.

题目大意 : 这道题 很好读懂 不需要翻译

解题思路:
就是构造矩阵 然后计算a[n][m]的值

我的思路就是
先把a[i][0]都为0的时候a[n][m]的值计算出来
再把a[0][i]都当成0的时候a[n][m]的值计算出来
把两者相加就是最终的结果了

所以我们就把这个问题分成两个子问题做就是了

一、
我先求的是a[0][i]都当成0的时候的a[n][m]值
这个其实很好求 先手写了一下发现有个规律

为了能明确的表达这个规律
在这里我们定义Sni为n个a[i][0]项和 SSni为Sni的前n项和 依此类推
未来了避免书写SSSSni的情况用mSni表示
例如3Sni就是SSSni; 这时候m=0就表示a[i][0]的值

我们通过手写能够知道a[n][m]的值为
(n-1)Smi+(n-2)Smi+…+(n-n)Smi;

而找这些值就很好处理了 只要构造一个上三角矩阵就行了

初始化a[i][j] 使每行都为a[i][0] 在乘上 上三角矩阵的k-1次幂就行了 切记a*上三角 不能反过来 因为矩阵只有结合律没有交换律

这样a[0][i]都当成0的时候的a[n][m]值就求出来了

二、
计算a[i][0]都为0的时候a[n][m]的值计算出来

计算这个的时候就容易多了 用我们要的结果就是计算数列的前n项和的前n项和的前n项和 至于有多少层就看n的值 n是几就是几层

这个矩阵就明显复杂一点
10 0 10 10 10 10 10 10 10 10 10 10
1 1 1 1 1 1 1 1 1 1 1 1
0 0 1 1 1 1 1 1 1 1 1 1
0 0 0 1 1 1 1 1 1 1 1 1
0 0 0 0 1 1 1 1 1 1 1 1
0 0 0 0 0 1 1 1 1 1 1 1
0 0 0 0 0 0 1 1 1 1 1 1
0 0 0 0 0 0 0 1 1 1 1 1
0 0 0 0 0 0 0 0 1 1 1 1
0 0 0 0 0 0 0 0 0 1 1 1
0 0 0 0 0 0 0 0 0 0 1 1
0 0 0 0 0 0 0 0 0 0 0 1

这是我构造出来的b矩阵
还有a矩阵 是

233 3 233 233 233 233 233 233 233 233 233 233
下面的值不重要

a矩阵每项的值分别是
a[n] 3(a[n+1]-a[n]*10) 剩下的就是从1层前n项和到10层前n项和

上面解释过

最后n是几就选择第几层的前n项和

这样就把a[i][0]都为0的时候a[n][m]的值计算出来

最后两者相加就出现结果了

//因为分成两遍做得 第二次初始化错误 导致模拟赛后1分54秒才调好 虽然1发ac了但是很不爽啊
这里写图片描述

附本题代码

-------------------------------------.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# include <iostream>
# include<stdio.h>
# include<algorithm>
# include<string.h>
using namespace std;

# define LL long long int

const int MOD = 1e7+7;
const int M = 12;

struct Matrix
{
LL m[20][20];
} a,b;
int n,m;


Matrix operator * (Matrix a,Matrix b)
{
Matrix c;
for(int i=0; i<M; i++) //初始化矩阵
for(int j=0; j<M; j++)
c.m[i][j]= 0;

for(int k=0; k<M; k++)
for(int i=0; i<M; i++) //实现矩阵乘法
{
if(a.m[i][k] <= 0) continue;
for(int j=0; j<M; j++)
{
if(b.m[k][j] <= 0) continue;
c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j]+MOD)%MOD;
}
}
return c;
}

Matrix operator ^ (Matrix a,LL b)
{
Matrix c;
for(int i=0; i<M; i++) //初始化单位矩阵
for(int j=0; j<M; j++)
c.m[i][j]= ( i == j );

while(b)
{
if(b&1) c= c * a ;
b >>= 1;
a = a * a ;
}

return c;
}


void init1()
{

for(int i=0; i<M; i++)
{
for(int j=0; j<M; j++)
{
b.m[i][j]=0;
}
}

for(int i=0; i<M; i++)
{
for(int j=i; j<M; j++)
{
b.m[i][j]=1;
}
b.m[0][i]=10;
}

b.m[0][1] = 0, b.m[1][0] = 1 ;

return ;
}

void init2()
{
for(int i=0; i<M; i++)
for(int j=0; j<M; j++)
b.m[i][j]=0;

for(int i=0; i<M; i++)
for(int j=i; j<M; j++)
b.m[i][j]=1;

return ;
}

int main()
{
init1();

while(~scanf("%d%d",&n,&m))
{
init1();

for(int i=0;i<M;i++)
a.m[0][i]=233;
a.m[0][1]=3;

b=b^(m-1);
a=a*b;

LL ans = a.m[0][n+1];

for(int i=1; i<=n; i++)
{
scanf("%d",&a.m[i][0]);
for(int j=0; j<M; j++)
a.m[i][j]=a.m[i][0]%MOD;
}

for(int i=0;i<M;i++)
a.m[0][i]=0;


init2();

b=b^(m-1);
a=a*b;

for(int i=1;i<=n;i++)
ans = (ans + a.m[i][n-i]) % MOD;

printf("%I64d\n",ans);
}
return 0;
}