HDU-5015
题意:有一个矩阵横排第一行初始是0,233,2333,23333…,然后给出计算公式a[i][j] = a[i - 1][j] + a[i][j - 1],然后给出了n和m和第一列的各值要求计算a[n][m]的值。
可以得出
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int mod = 10000007;
int n, m;
struct Mat {
int mat[12][12];
};
Mat operator*(Mat a, Mat b) {//重载*,矩阵乘模板
Mat c;
memset(c.mat, 0, sizeof c.mat);
for (int i = 0; i <= n + 1; i++)
for (int j = 0; j <= n + 1; j++)
for (int k = 0; k <= n + 1; k++)
c.mat[i][j] = (c.mat[i][j] + (ll)a.mat[i][k] * b.mat[k][j]) % mod;
return c;
}
Mat qkpow(Mat a, int b) {
Mat res;
memset(res.mat, 0, sizeof res.mat);
for (int i = 0; i <= n + 1; i++)res.mat[i][i] = 1;//初始化为单位矩阵
while (b) {
if (b & 1)res = res * a;
a = a * a;
b >>= 1;
}
return res;
}
int main() {
while (~scanf("%d%d", &n, &m)) {
Mat sum, tmp;
memset(sum.mat, 0, sizeof sum.mat);
memset(tmp.mat, 0, sizeof tmp.mat);
sum.mat[0][0] = 23;
sum.mat[n + 1][0] = 3;
for (int i = 1; i <= n; i++)scanf("%d", &sum.mat[i][0]);
if (m == 0) {
if (n == 0)puts("0");
else printf("%d\n", sum.mat[n][0]);
continue;
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= i; j++)
tmp.mat[i][j] = 1;
for (int i = 0; i <= n; i++)tmp.mat[i][0] = 10;
for (int i = 0; i <= n + 1; i++)tmp.mat[i][n + 1] = 1;
sum = qkpow(tmp, m) * sum;
printf("%d\n", sum.mat[n][0]);
}
return 0;
}
HDU-4990
构造方法一(直接构造):
s
u
m
=
sum=
sum={
a
[
0
]
,
0
,
5
,
0
,
5
a[0],0,5,0,5
a[0],0,5,0,5}
t
m
p
=
tmp=
tmp=
{{
2
,
0
,
0
2,0,0
2,0,0},
{
1
,
1
,
0
1,1,0
1,1,0}.
{
1
,
0
,
−
1
1,0,-1
1,0,−1}
}
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
int n, mod;
struct Mat {
ll mat[3][3];
} tmp;
Mat operator*(Mat a, Mat b) {
Mat c;
memset(c.mat, 0, sizeof c.mat);
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
for (int k = 0; k < 3; k++)
c.mat[i][j] = (c.mat[i][j] + a.mat[i][k] * b.mat[k][j]) % mod;
return c;
}
Mat qkpow(Mat a, int b) {
Mat sum;
memset(sum.mat, 0, sizeof sum.mat);
for (int i = 0; i < 3; i++)sum.mat[i][i] = 1;
while (b) {
if (b & 1)sum = sum * a;
a = a * a;
b >>= 1;
}
return sum;
}
int main() {
while (~scanf("%d%d", &n, &mod)) {
mod <<= 1;
memset(tmp.mat, 0, sizeof tmp.mat);
tmp.mat[0][0] = 2;
tmp.mat[1][0] = tmp.mat[1][1] = tmp.mat[2][0] = 1;
tmp.mat[2][2] = -1;
tmp = qkpow(tmp, n);
mod >>= 1;
printf("%lld\n", ((tmp.mat[1][0] + tmp.mat[2][0] >> 1) % mod + mod) % mod);
}
return 0;
}
构造方法二:(先推公式再构造)
若n为偶数
a
[
n
]
=
2
∗
a
[
n
−
1
]
=
a
[
n
−
1
]
+
2
∗
a
[
n
−
2
]
+
1
a[n]=2*a[n-1]=a[n-1]+2*a[n-2]+1
a[n]=2∗a[n−1]=a[n−1]+2∗a[n−2]+1
若n为奇数
a
[
n
]
=
2
∗
a
[
n
−
1
]
+
1
=
a
[
n
−
1
]
+
2
∗
a
[
n
−
2
]
+
1
a[n]=2*a[n-1]+1=a[n-1]+2*a[n-2]+1
a[n]=2∗a[n−1]+1=a[n−1]+2∗a[n−2]+1
显然这两者相同
那么根据公式就好推了
s
u
m
=
sum=
sum={
a
[
0
]
,
a
[
1
]
,
1
a[0],a[1],1
a[0],a[1],1}
tmp=
{{0,2,0},
{1,1,0}.
{0,1,1}
}
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
int n, mod;
struct Mat {
ll mat[3][3];
}sum, tmp;
Mat operator*(Mat a, Mat b) {
Mat c;
memset(c.mat, 0, sizeof c.mat);
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
for (int k = 0; k < 3; k++)
c.mat[i][j] = (c.mat[i][j] + a.mat[i][k] * b.mat[k][j]) % mod;
return c;
}
Mat qkpow(Mat a, int b) {
Mat sum;
memset(sum.mat, 0, sizeof sum.mat);
for (int i = 0; i < 3; i++)sum.mat[i][i] = 1;
while (b) {
if (b & 1)sum = sum * a;
a = a * a;
b >>= 1;
}
return sum;
}
int main() {
while (~scanf("%d%d", &n, &mod)) {
memset(tmp.mat, 0, sizeof tmp.mat);
memset(sum.mat, 0, sizeof sum.mat);
sum.mat[0][1]=sum.mat[0][2]=1;
tmp.mat[0][1] = 2;
tmp.mat[1][0] = tmp.mat[1][1] = tmp.mat[2][1] = tmp.mat[2][2] = 1;
sum = sum * qkpow(tmp, n);
printf("%d\n", sum.mat[0][0]);
}
return 0;
}
HDU - 4549
题意:
F
[
0
]
=
a
,
F
[
1
]
=
b
,
F
[
n
]
=
F
[
n
−
1
]
∗
F
[
n
−
2
]
(
n
>
1
)
F[0] = a,F[1] = b,F[n] = F[n-1] * F[n-2] ( n > 1 )
F[0]=a,F[1]=b,F[n]=F[n−1]∗F[n−2](n>1),求
F
[
n
]
F[n]
F[n]
可以发现
F
[
n
]
=
a
f
[
n
−
1
]
∗
b
f
[
n
]
F[n]=a^{f[n-1]}*b^{f[n]}
F[n]=af[n−1]∗bf[n]
由于f[n]很大,根据欧拉公式
a
x
%
p
=
a
x
%
p
h
i
[
p
]
%
p
a^{x}\% p=a^{x\%phi[p]}\%p
ax%p=ax%phi[p]%p
由于
p
=
1
e
9
+
7
p=1e9+7
p=1e9+7,所以
p
h
i
[
p
]
=
p
−
1
phi[p]=p-1
phi[p]=p−1
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef long long ll;
const int mod = 1000000007;
struct Mat {
ll mat[2][2];
} sum, tmp;
ll a, b, n;
Mat operator*(Mat a, Mat b) {
Mat c;
memset(c.mat, 0, sizeof c.mat);
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
for (int k = 0; k < 2; k++)
c.mat[i][j] = (c.mat[i][j] + a.mat[i][k] * b.mat[k][j]) % (mod - 1);
return c;
}
Mat qkpow(Mat a, int b) {
Mat sum;
memset(sum.mat, 0, sizeof sum.mat);
for (int i = 0; i < 2; i++)sum.mat[i][i] = 1;
while (b) {
if (b & 1)sum = sum * a;
a = a * a;
b >>= 1;
}
return sum;
}
ll qkpow(ll a, ll b) {
ll sum = 1;
while (b) {
if (b & 1)sum = sum * a % mod;
a = a * a % mod;
b >>= 1;
}
return sum;
}
int main() {
while (~scanf("%lld%lld%lld", &a, &b, &n)) {
memset(sum.mat, 0, sizeof sum.mat);
memset(tmp.mat, 0, sizeof tmp.mat);
sum.mat[0][1] = 1;
tmp.mat[0][1] = tmp.mat[1][1] = tmp.mat[1][0] = 1;
if (n == 0 || n == 1) {
if (!n)printf("%lld\n", a);
else printf("%lld\n", b);
continue;
}
sum = sum * qkpow(tmp, n - 1);
ll pa = sum.mat[0][0], pb = sum.mat[0][1];
printf("%d\n", qkpow(a, pa) * qkpow(b, pb) % mod);
}
return 0;
}
HDU - 4965
若直接求
(
A
∗
B
)
n
∗
n
(A*B)^{n*n}
(A∗B)n∗n内存会爆
(
A
∗
B
)
n
∗
n
=
(
A
∗
B
)
∗
(
A
∗
B
)
…
…
(
A
∗
B
)
=
A
∗
(
B
∗
A
)
∗
(
B
∗
A
)
…
…
(
B
∗
A
)
∗
B
=
A
∗
(
B
∗
A
)
n
∗
n
−
1
∗
B
(A*B)^{n*n}=(A*B)*(A*B)……(A*B)= A*(B*A)*(B*A)……(B*A)*B=A*(B*A)^{n*n-1}*B
(A∗B)n∗n=(A∗B)∗(A∗B)……(A∗B)=A∗(B∗A)∗(B∗A)……(B∗A)∗B=A∗(B∗A)n∗n−1∗B
B*A是一个最大6*6的矩阵,这样就不会爆内存了,且提升速度
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
int n, m;
struct Mat {
ll mat[6][6];
void init(int x) {
memset(mat, 0, sizeof mat);
for (int i = 0; i < 6; i++)mat[i][i] = x;
}
Mat operator*(Mat &a) {
Mat c;
memset(c.mat, 0, sizeof c.mat);
for (int i = 0; i < m; i++)
for (int j = 0; j < m; j++)
for (int k = 0; k < m; k++)
c.mat[i][j] = (c.mat[i][j] + mat[i][k] * a.mat[k][j]) % 6;
return c;
}
} c;
int a[1010][6], b[6][1010], d[1010][6], res[1010][1010];
Mat qkpow(Mat a, int b) {
Mat sum;
sum.init(1);
while (b) {
if (b & 1)sum = sum * a;
a = a * a;
b >>= 1;
}
return sum;
}
int main() {
while (scanf("%d%d", &n, &m), n + m) {
c.init(0);
memset(d, 0, sizeof d);
memset(res, 0, sizeof res);
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
scanf("%d", &a[i][j]);
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
scanf("%d", &b[i][j]);
for (int i = 0; i < m; i++)
for (int j = 0; j < m; j++)
for (int k = 0; k < n; k++)
c.mat[i][j] = (c.mat[i][j] + b[i][k] * a[k][j]) % 6;
c = qkpow(c, n * n - 1);
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
for (int k = 0; k < m; k++)
d[i][j] = (d[i][j] + a[i][k] * c.mat[k][j]) % 6;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
for (int k = 0; k < m; k++)
res[i][j] = (res[i][j] + d[i][k] * b[k][j]) % 6;
int ans = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
ans += res[i][j];
cout << ans << endl;
}
return 0;
}
UVA - 10655
题意:给定
p
,
q
p,q
p,q分别表示
a
+
b
,
a
∗
b
a+b,a*b
a+b,a∗b的值,再给定n,求
a
n
+
b
n
a^n+b^n
an+bn
记
F
[
n
]
=
a
n
+
b
n
F[n]=a^n+b^n
F[n]=an+bn
则
F
[
n
]
∗
(
a
+
b
)
=
a
n
+
1
+
b
n
+
1
+
(
a
∗
b
)
(
b
n
−
1
+
a
n
−
1
)
=
F
[
n
+
1
]
+
q
∗
F
[
n
−
1
]
F[n]*(a+b)=a^{n+1}+b^{n+1}+(a*b)(b^{n-1}+a^{n-1}) =F[n+1]+q*F[n-1]
F[n]∗(a+b)=an+1+bn+1+(a∗b)(bn−1+an−1)=F[n+1]+q∗F[n−1]
即
F
[
n
]
=
F
[
n
−
1
]
∗
p
−
q
∗
F
[
n
−
1
]
F[n]=F[n-1]*p-q*F[n-1]
F[n]=F[n−1]∗p−q∗F[n−1]
所以
s
u
m
=
F
[
0
]
,
F
[
1
]
sum={F[0],F[1]}
sum=F[0],F[1]
t
m
p
=
tmp=
tmp=
{{
0
,
−
q
0,-q
0,−q},
{
1
,
p
1,p
1,p}
}
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
ll p, q, n;
struct Mat {
ll mat[2][2];
void init(ll x) {
memset(mat, 0, sizeof mat);
for (int i = 0; i < 2; i++)mat[i][i] = x;
}
Mat operator*(Mat b) {
Mat c;
memset(c.mat, 0, sizeof c.mat);
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
for (int k = 0; k < 2; k++)
c.mat[i][j] += mat[i][k] * b.mat[k][j];
return c;
}
} sum, tmp;
Mat qkpow(Mat a, ll b) {
Mat sum;
sum.init(1);
while (b) {
if (b & 1)sum = sum * a;
a = a * a;
b >>= 1;
}
return sum;
}
int main() {
while (scanf("%lld%lld%lld", &p, &q, &n) == 3) {
tmp.init(0);
tmp.mat[0][1] = -q;
tmp.mat[1][0] = 1, tmp.mat[1][1] = p;
tmp = qkpow(tmp, n);
printf("%lld\n", tmp.mat[0][0] * 2 + tmp.mat[1][0] * p);
}
return 0;
}
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int mod = 1024;
typedef long long ll;
int t, n;
struct Mat {
ll mat[2][2];
void init(ll x) {
memset(mat, 0, sizeof mat);
for (int i = 0; i < 2; i++)mat[i][i] = x;
}
Mat operator*(Mat b) {
Mat c;
memset(c.mat, 0, sizeof c.mat);
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
for (int k = 0; k < 2; k++)
c.mat[i][j] = (c.mat[i][j] + mat[i][k] * b.mat[k][j]) % mod;
return c;
}
} tmp;
Mat qkpow(Mat a, ll b) {
Mat sum;
sum.init(1);
while (b) {
if (b & 1)sum = sum * a;
a = a * a;
b >>= 1;
}
return sum;
}
int main() {
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
memset(tmp.mat, 0, sizeof tmp.mat);
tmp.mat[0][0] = 5;
tmp.mat[0][1] = 2;
tmp.mat[1][0] = 12;
tmp.mat[1][1] = 5;
tmp = qkpow(tmp, n - 1);
printf("%d\n", (2 * (5 * tmp.mat[0][0] + 2 * tmp.mat[1][0]) - 1) % mod);
}
return 0;
}
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int mod = 1024;
typedef long long ll;
ll a, b, m, n;
struct Mat {
ll mat[2][2];
void init(ll x) {
memset(mat, 0, sizeof mat);
for (int i = 0; i < 2; i++)mat[i][i] = x;
}
Mat operator*(Mat b) {
Mat c;
memset(c.mat, 0, sizeof c.mat);
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
for (int k = 0; k < 2; k++)
c.mat[i][j] = (c.mat[i][j] + mat[i][k] * b.mat[k][j]) % m;
return c;
}
} tmp;
Mat qkpow(Mat a, ll b) {
Mat sum;
sum.init(1);
while (b) {
if (b & 1)sum = sum * a;
a = a * a;
b >>= 1;
}
return sum;
}
int main() {
while (scanf("%d%d%d%d", &a, &b, &n, &m) == 4) {
memset(tmp.mat, 0, sizeof tmp.mat);
tmp.mat[0][0] = tmp.mat[1][1] = a;
tmp.mat[0][1] = 1;
tmp.mat[1][0] = b;
tmp = qkpow(tmp, n - 1);
printf("%d\n", 2 * (a * tmp.mat[0][0] + tmp.mat[1][0]) % m);
}
return 0;
}
UVA - 11149
题意,等比矩阵求和
思路:二分幂求和
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long ll;
int n, m;
struct Mat {
ll mat[40][40];
void init(ll x, int n) {
memset(mat, 0, sizeof mat);
for (int i = 0; i < n; i++)mat[i][i] = x;
}
Mat operator*(Mat b) {
Mat c;
memset(c.mat, 0, sizeof c.mat);
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
for (int k = 0; k < n; k++)
c.mat[i][j] = (c.mat[i][j] + mat[i][k] * b.mat[k][j]) % 10;
return c;
}
Mat operator+(Mat b) {
Mat c;
memset(c.mat, 0, sizeof c.mat);
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
c.mat[i][j] = (mat[i][j] + b.mat[i][j]) % 10;
return c;
}
} a, q;
Mat qkpow(Mat a, ll b) {
Mat sum;
sum.init(1, n);
while (b) {
if (b & 1)sum = sum * a;
a = a * a;
b >>= 1;
}
return sum;
}
void out(Mat a) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n - 1; j++)
printf("%d ", a.mat[i][j]);
printf("%d\n", a.mat[i][n - 1]);
}
puts("");
}
Mat sum(ll n) {
if (n == 1)return a;
Mat aa = qkpow(a, n + 1 >> 1);
Mat s = (q + aa) * sum(n >> 1);
if (n & 1)return s + aa;
return s;
}
int main() {
while (scanf("%d%d", &n, &m), n) {
q.init(1, n);
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
scanf("%lld", &a.mat[i][j]), a.mat[i][j] %= 10;
out(sum(m));
}
return 0;
}
UVA - 11551
题意:给n个数和r。接在输入n行,表示每次将第i个数变成它后面几个位置的和。重复r次
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int mod = 1000;
int t, n, m;
struct Mat {
int mat[50][50];
void init(int x, int n) {
memset(mat, 0, sizeof mat);
for (int i = 0; i < n; i++)mat[i][i] = x;
}
Mat operator*(Mat b) {
Mat c;
memset(c.mat, 0, sizeof c.mat);
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
for (int k = 0; k < n; k++)
c.mat[i][j] = (c.mat[i][j] + mat[i][k] * b.mat[k][j]) % mod;
return c;
}
} a, b;
Mat qkpow(Mat a, int b) {
Mat sum;
sum.init(1, n);
while (b) {
if (b & 1)sum = sum * a;
a = a * a;
b >>= 1;
}
return sum;
}
int main() {
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &m);
b.init(0, n);
a.init(0, n);
for (int i = 0; i < n; i++)scanf("%d", &a.mat[0][i]);
for (int i = 0, s, j; i < n; i++) {
scanf("%d", &s);
while (s--) {
scanf("%d", &j);
b.mat[j][i] = 1;
}
}
if (!m) {
for (int i = 0; i < n - 1; i++)printf("%d ", a.mat[0][i]);
printf("%d", a.mat[0][n - 1]);
continue;
}
b = a * qkpow(b, m);
for (int i = 0; i < n - 1; i++)printf("%d ", b.mat[0][i]);
printf("%d\n", b.mat[0][n - 1]);
}
return 0;
}
HDU - 4686
a
[
i
]
∗
b
[
i
]
=
a
[
i
−
1
]
∗
b
[
i
−
1
]
∗
A
X
∗
B
X
+
A
Y
∗
B
X
∗
b
[
i
−
1
]
+
B
Y
∗
A
X
∗
a
[
i
−
1
]
+
A
Y
∗
b
Y
a[i]*b[i]=a[i-1]*b[i-1]*AX*BX+AY*BX*b[i-1]+BY*AX*a[i-1]+AY*bY
a[i]∗b[i]=a[i−1]∗b[i−1]∗AX∗BX+AY∗BX∗b[i−1]+BY∗AX∗a[i−1]+AY∗bY
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int mod = 1e9 + 7;
typedef long long ll;
ll n;
ll a0, b0, ax, bx, ay, by;
struct Mat {
ll mat[5][5];
void init(int x) {
memset(mat, 0, sizeof mat);
for (int i = 0; i < 5; i++)mat[i][i] = x;
}
Mat operator*(Mat b) {
Mat c;
memset(c.mat, 0, sizeof c.mat);
for (int i = 0; i < 5; i++)
for (int j = 0; j < 5; j++)
for (int k = 0; k < 5; k++)
c.mat[i][j] = (c.mat[i][j] + mat[i][k] * b.mat[k][j]) % mod;
return c;
}
} a, b;
Mat qkpow(Mat a, ll b) {
Mat sum;
sum.init(1);
while (b) {
if (b & 1)sum = sum * a;
a = a * a;
b >>= 1;
}
return sum;
}
int main() {
while (scanf("%lld", &n) == 1) {
scanf("%lld%lld%lld%lld%lld%lld", &a0, &ax, &ay, &b0, &bx, &by);
a.init(0);
b.init(0);
b.mat[0][0] = ax * bx % mod;
b.mat[1][0] = ay * bx % mod;
b.mat[2][0] = by * ax % mod;
b.mat[4][0] = ay * by % mod;
b.mat[1][1] = bx % mod;
b.mat[4][1] = by % mod;
b.mat[2][2] = ax % mod;
b.mat[4][2] = ay % mod;
b.mat[0][3] = b.mat[3][3] = b.mat[4][4] = 1;
a.mat[0][0] = a0 * b0 % mod;
a.mat[0][1] = b0 % mod;
a.mat[0][2] = a0 % mod;
a.mat[0][4] = 1;
b = a * qkpow(b, n);
printf("%d\n", b.mat[0][3]);
}
return 0;
}
题意:有一个细胞自动机,它是一个由 n 个元素组成的环,每个元素的值都必须是 mod m意义下的。现在你需要对这个环进行 k 次操作,每次操作你需要把这个环内每个元素更新成与它距离不超过 d 的所有元素之和(包括自己)。注:每一个新的元素也必须是 mod m 意义下的。
思路:发现需要构造的矩阵为循环矩阵
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long ll;
int n, mod, d, k;
struct Mat {
ll mat[500];
Mat operator*(Mat b) {//循环矩阵乘
Mat c;
memset(c.mat, 0, sizeof c.mat);
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
c.mat[i] = (c.mat[i] + mat[(j - i + n) % n] * b.mat[j]) % mod;
return c;
}
} a, b;
Mat qkpow(Mat a, ll b) {
Mat sum;
memset(sum.mat, 0, sizeof sum.mat);
sum.mat[0] = 1;
while (b) {
if (b & 1)sum = sum * a;
a = a * a;
b >>= 1;
}
return sum;
}
int main() {
while (scanf("%d%d%d%d", &n, &mod, &d, &k) == 4) {
for (int i = 0; i < n; i++)scanf("%d", &a.mat[i]);
memset(b.mat, 0, sizeof b.mat);
for (int i = 0; i <= d; i++)b.mat[i] = 1;
for (int i = n - 1; i > n - 1 - d; i--)b.mat[i] = 1;
b = qkpow(b, k) * a;
for (int i = 0; i < n - 1; i++)printf("%d ", b.mat[i]);
printf("%d\n", b.mat[n - 1]);
}
return 0;
}
UVA - 11651
题意:有一个
b
a
s
e
(
2
≤
b
a
s
e
≤
6
)
base(2≤base≤6)
base(2≤base≤6)进制系统,这里面的数都是整数,不含前导
0
0
0,相邻两个数字不相同。
而且每个数字有一个得分
s
c
o
r
e
(
1
≤
s
c
o
r
e
≤
109
)
score(1≤score≤109)
score(1≤score≤109),得分为 相邻两个数字之差的平方之和。
给出
b
a
s
e
base
base和
s
c
o
r
e
score
score,求满足条件的整数的个数
m
o
d
mod
mod
2
32
2^{32}
232。
思路:
首先考虑DP的做法:
设
d
p
(
i
,
j
)
dp(i,j)
dp(i,j)表示满足当前分数为i最后一个数字是j的数字的个数。
递推就是枚举下一个数字
k
k
k,就有转移方程:
d
p
(
i
+
d
,
k
)
=
∑
d
p
(
i
,
j
)
dp(i+d,k)=∑dp(i,j)
dp(i+d,k)=∑dp(i,j),其中
k
≠
j
k≠j
k=j且
d
=
(
k
−
j
)
2
d=(k−j)^2
d=(k−j)2
这种方法的复杂度使
O
(
b
a
s
e
2
⋅
s
c
o
r
e
)
O(base^2⋅score)
O(base2⋅score)的。
考虑矩阵优化:
因为状态转移中,能得到的最大分数是
(
b
a
s
e
−
1
)
2
(base−1)^2
(base−1)2,所以我们的转移矩阵只要保留前面
(
b
a
s
e
−
1
)
2
(base−1)^2
(base−1)2个
s
c
o
r
e
score
score的信息就行了。
用语言不方便表达,我举具体例子,
当
b
a
s
e
=
3
base=3
base=3时,有如下转移:
上面9行很好理解,就是一个错位。
下面3行才是状态的转移。
容易看出,我们的矩阵的边长最大会达到
6
∗
(
6
−
1
)
2
=
150
6*(6−1)^2=150
6∗(6−1)2=150
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
typedef unsigned int ul;
int t, n, m, cas, N;
struct Mat {
ul mat[150][150];
void init(ul x, int n) {
memset(mat, 0, sizeof mat);
for (int i = 0; i < n; i++)mat[i][i] = x;
}
Mat operator*(Mat b) {
Mat c;
memset(c.mat, 0, sizeof c.mat);
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
for (int k = 0; k < N; k++)
c.mat[i][j] += mat[i][k] * b.mat[k][j];
return c;
}
} a, b;
Mat qkpow(Mat a, int b) {
Mat sum;
sum.init(1, N);
while (b) {
if (b & 1)sum = sum * a;
a = a * a;
b >>= 1;
}
return sum;
}
ul dp[25][6];// i:score j:last digit
int main() {
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &m);
int nn = (n - 1) * (n - 1);
N = n * nn;
b.init(0, N);
a.init(0, N);
memset(dp, 0, sizeof dp);
// dp
for (int i = 1; i < n; i++)dp[0][i] = 1;
for (int i = 0; i < nn; i++)
for (int j = 0; j < n; j++)
for (int k = 0; k < n; k++) {
int d = (j - k) * (j - k);
if (!d || i + d >= nn)continue;
dp[i + d][k] += dp[i][j];
}
for (int i = 0; i < nn; i++)
for (int j = 0; j < n; j++)
a.mat[i * n + j][0] = dp[i][j];
for (int i = 0; i < N - n; i++)
b.mat[i][n + i] = 1;
for (int j = 0; j < n; j++)
for (int k = 0; k < n; k++) {
int d = (j - k) * (j - k);
if (!d || nn - d < 0)continue;
b.mat[(nn - 1) * n + j][(nn - d) * n + k] = 1;
}
b = qkpow(b, m) * a;
ul res = 0;
for (int i = 0; i < n; i++)res += b.mat[i][0];
printf("Case %d: %u\n", ++cas, res);
}
return 0;
}
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
struct Mat {
ll mat[83][83];
void init(ll x) {
memset(mat, 0, sizeof mat);
for (int i = 0; i < 83; i++)mat[i][i] = x;
}
Mat operator*(Mat b) {
Mat c;
memset(c.mat, 0, sizeof c.mat);
for (int i = 0; i < 83; i++)
for (int j = 0; j < 83; j++)
for (int k = 0; k < 83; k++)
c.mat[i][j] = (c.mat[i][j] + mat[i][k] * b.mat[k][j]) % mod;
return c;
}
} a, b;
Mat qkpow(Mat a, ll b) {
Mat sum;
sum.init(1);
while (b) {
if (b & 1)sum = sum * a;
a = a * a;
b >>= 1;
}
return sum;
}
ll n, k;
ll c[50][50];
void init() {
for (int i = 0; i <= 40; i++)
for (int j = 0; j <= i; j++)
if (!j)c[i][j] = 1;
else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
}
int main() {
cin >> n >> k;
init();
b.init(0);
b.mat[0][0] = 1;
for (int i = 0; i <= k; i++)b.mat[0][i + 1] = c[k][i];
for (int i = 0; i <= k; i++)b.mat[0][k + i + 2] = c[k][i];
for (int i = 1; i <= k + 1; i++) {
for (int j = 1; j <= i; j++)b.mat[i][j] = c[i - 1][j - 1];
for (int j = 1; j <= i; j++)b.mat[i][j + k + 1] = c[i - 1][j - 1];
}
for (int i = 1; i <= k + 1; i++)
for (int j = 1; j <= i; j++)
b.mat[i + k + 1][j] = c[i - 1][j - 1];
b = qkpow(b, n - 1);
int res = 0;
for (int i = 0; i < 2 * k + 3; i++)res = (res + b.mat[0][i]) % mod;
printf("%d\n", res);
return 0;
}