模板题。
感觉写完结构体就可以为所欲为了。
#include
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std;
typedef long long ll;
const int MAXN = 100 + 10;
struct Matrix
{
int n, m;
ll c[MAXN][MAXN];
Matrix() { memset(c, 0, sizeof(c)); }
void read()
{
_for(i, 1, n)
_for(j, 1, m)
scanf("%lld", &c[i][j]);
}
Matrix operator * (const Matrix& a)
{
Matrix r;
r.n = n; r.m = a.m;
_for(i, 1, r.n)
_for(j, 1, r.m)
_for(k, 1, m)
r.c[i][j] += c[i][k] * a.c[k][j];
return r;
}
void print()
{
_for(i, 1, n)
{
_for(j, 1, m)
printf("%lld ", c[i][j]);
puts("");
}
}
}A, B, C;
int main()
{
scanf("%d%d", &A.n, &A.m); B.n = A.m;
A.read();
scanf("%d", &B.m);
B.read();
C = A * B;
C.print();
return 0;
}
大概总结一下构造矩阵的方法
我们可以构造一个1x2的矩阵
使得
A是一个2*2的矩阵
可以求得A是
0 1
1 1
矩阵快速幂即可
#include
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std;
typedef long long ll;
const int MAXN = 100 + 10;
int MOD, k;
struct Matrix
{
int n, m;
ll c[MAXN][MAXN];
Matrix() { memset(c, 0, sizeof(c)); }
Matrix operator * (const Matrix& a)
{
Matrix r;
r.n = n; r.m = a.m;
_for(i, 1, r.n)
_for(j, 1, r.m)
_for(k, 1, m)
r.c[i][j] = (r.c[i][j] + c[i][k] * a.c[k][j] % MOD) % MOD;
return r;
}
};
Matrix power(Matrix a, int b)
{
Matrix res; res.n = res.m = 2;
_for(i, 1, res.n) res.c[i][i] = 1;
for(; b; b >>= 1)
{
if(b & 1) res = res * a;
a = a * a;
}
return res;
}
int main()
{
scanf("%d%d", &k, &MOD);
Matrix A; A.n = A.m = 2;
A.c[1][2] = A.c[2][1] = A.c[2][2] = 1;
A = power(A, k - 1);
Matrix ans; ans.n = 1; ans.m = 2;
ans.c[1][1] = ans.c[1][2] = 1;
ans = ans * A;
printf("%lld\n", ans.c[1][1]);
return 0;
}
在矩阵中加入一个sn进去就好了。
构造矩阵记得往后推以及分解
#include
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std;
typedef long long ll;
const int MAXN = 100 + 10;
int MOD, k;
struct Matrix
{
int n, m;
ll c[MAXN][MAXN];
Matrix() { memset(c, 0, sizeof(c)); }
Matrix operator * (const Matrix& a)
{
Matrix r;
r.n = n; r.m = a.m;
_for(i, 1, r.n)
_for(j, 1, r.m)
_for(k, 1, m)
r.c[i][j] = (r.c[i][j] + c[i][k] * a.c[k][j] % MOD) % MOD;
return r;
}
};
Matrix power(Matrix a, int b)
{
Matrix res; res.n = res.m = 3;
_for(i, 1, res.n) res.c[i][i] = 1;
for(; b; b >>= 1)
{
if(b & 1) res = res * a;
a = a * a;
}
return res;
}
int main()
{
scanf("%d%d", &k, &MOD);
Matrix A; A.n = A.m = 3;
A.c[1][1] = A.c[2][1] = A.c[3][1] = 1;
A.c[3][2] = A.c[3][3] = A.c[2][3] = 1;
A = power(A, k - 2);
Matrix ans; ans.n = 1; ans.m = 3;
ans.c[1][1] = 2;
ans.c[1][2] = ans.c[1][3] = 1;
ans = ans * A;
printf("%lld\n", ans.c[1][1]);
return 0;
}
这道题推的真的太爽了!!
看到有n*fn
那么我们就再矩阵中加入n*fn
所以就是
推到
所以可以构造出A
1 0 0 0 0
1 0 1 0 0
1 1 1 0 0
1 0 1 1 1
2 0 2 1 0
初始矩阵为[3,1,2,1,1]
#include
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std;
typedef long long ll;
const int MAXN = 100 + 10;
int MOD, k;
struct Matrix
{
int n, m;
ll c[MAXN][MAXN];
Matrix() { memset(c, 0, sizeof(c)); }
Matrix operator * (const Matrix& a)
{
Matrix r;
r.n = n; r.m = a.m;
_for(i, 1, r.n)
_for(j, 1, r.m)
_for(k, 1, m)
r.c[i][j] = (r.c[i][j] + c[i][k] * a.c[k][j] % MOD) % MOD;
return r;
}
};
Matrix power(Matrix a, int b)
{
Matrix res; res.n = res.m = 5;
_for(i, 1, res.n) res.c[i][i] = 1;
for(; b; b >>= 1)
{
if(b & 1) res = res * a;
a = a * a;
}
return res;
}
int main()
{
scanf("%d%d", &k, &MOD);
if(k == 1) { puts("1"); return 0; }
Matrix A; A.n = A.m = 5;
A.c[1][1] = 1;
A.c[2][1] = A.c[2][3] = 1;
A.c[3][1] = A.c[3][2] = A.c[3][3] = 1;
A.c[4][1] = A.c[4][3] = A.c[4][4] = A.c[4][5] = 1;
A.c[5][1] = A.c[5][3] = 2; A.c[5][4] = 1;
A = power(A, k - 2);
Matrix ans; ans.n = 1; ans.m = 5;
ans.c[1][1] = 3;
ans.c[1][2] = ans.c[1][4] = ans.c[1][5] = 1;
ans.c[1][3] = 2;
ans = ans * A;
printf("%lld\n", ans.c[1][1]);
return 0;
}
这道题写了好久!!!
这道题用到了三个知识点,kmp,dp,矩阵乘法。
设f[i][j]为前i个字符的后缀匹配到不吉利串的前j个字符的方案数(第一次见到这样的状态设计)
那么转移方程为f[i][next(j)] = sum(f[i-1][j])
从j到next(j)可以用kmp算法求出来
然后这个转移可以用矩阵快速幂来优化。
注意这里的矩阵和状态是相匹配的,所以下标一定从0开始
所以矩阵乘法真正的用途在与dp,如果题目给的n很大,
那么可以按照转移的方式来构造矩阵
#include
#define add(a, b) a = (a + b) % mod
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std;
const int MAXN = 30;
int next[MAXN], mod, m, n;
char s[MAXN];
struct Matrix
{
int n, m;
int c[MAXN][MAXN];
Matrix(int n, int m) : n(n), m(m) { memset(c, 0, sizeof(c)); }
Matrix operator * (const Matrix& a)
{
Matrix res(n, a.m);
REP(i, 0, res.n)
REP(j, 0, res.m)
REP(k, 0, m)
{
res.c[i][j] += c[i][k] * a.c[k][j];
res.c[i][j] %= mod;
}
return res;
}
};
void get_next()
{
next[1] = 0; int j = 0;
_for(i, 2, m)
{
while(j && s[j + 1] != s[i]) j = next[j];
if(s[j + 1] == s[i]) j++;
next[i] = j;
}
}
Matrix power(Matrix a, int b)
{
Matrix res(m, m);
REP(i, 0, m) res.c[i][i] = 1;
for(; b; b >>= 1)
{
if(b & 1) res = res * a;
a = a * a;
}
return res;
}
int main()
{
scanf("%d%d%d%s", &n, &m, &mod, s + 1);
get_next();
Matrix A(m, m);
REP(i, 0, m)
REP(d, 0, 10)
{
int j = i;
char ch = d + '0';
while(j && s[j + 1] != ch) j = next[j];
if(s[j + 1] == ch) j++;
if(j != m)add(A.c[i][j], 1);
}
Matrix ans(1, m);
ans.c[0][0] = 1;
ans = ans * power(A, n);
int sum = 0;
REP(i, 0, m)
add(sum, ans.c[0][i]);
printf("%d\n", sum);
return 0;
}
首先这道题如果边权值为1的话,矩阵自乘T次就是答案
但是这道题的边权最大为9
所以拆成9个点。
可以定义一个id为id(x, y) ((x - 1) * 9 + y),也就是说给每个点拆出来的点给个
编号,然后连边的时候连编号,y为1就最原始的点,y!=1都是衍生出来的。
注意连边的时候注意方向,一定要分清x坐标和y坐标,可以拿笔画一画
#include
#define id(x, y) ((x - 1) * 9 + y)
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std;
const int MAXN = 100 + 10;
const int mod = 2009;
int n, T;
struct Matrix
{
int n, m;
int c[MAXN][MAXN];
Matrix(int n, int m) : n(n), m(m) { memset(c, 0, sizeof(c)); }
Matrix operator * (const Matrix& a)
{
Matrix res(n, a.m);
_for(i, 1, res.n)
_for(j, 1, res.m)
_for(k, 1, m)
{
res.c[i][j] += c[i][k] * a.c[k][j];
res.c[i][j] %= mod;
}
return res;
}
};
Matrix power(Matrix a, int b)
{
Matrix res(n * 9, n * 9);
_for(i, 1, n * 9) res.c[i][i] = 1;
for(; b; b >>= 1)
{
if(b & 1) res = res * a;
a = a * a;
}
return res;
}
int main()
{
scanf("%d%d", &n, &T);
Matrix A(n * 9, n * 9);
_for(i, 1, n)
_for(j, 1, n)
{
int x; scanf("%1d", &x);
if(!x) continue;
A.c[id(i, x)][id(j, 1)] = 1;
}
_for(i, 1, n)
_for(j, 1, 8)
A.c[id(i, j)][id(i, j + 1)] = 1;
A = power(A, T);
printf("%d\n", A.c[id(1, 1)][id(n, 1)]);
return 0;
}
我又独立做出省选题了,这次只WA了一次
但是这次WA显然可以避免的,自己要养成写完程序静态查错的习惯,不要直接交,然后再改。
考试的时候只能交一次。还有头脑一定要非常清晰自己在干什么。
这道题关键在于用到了lcm的思想。
美人鱼只有2,3,4,那么显然12秒之后又会重复。
那么我们可以针对每一秒构造出转移矩阵,注意是每一秒,不是前几秒,我一开始写的是前几秒。
每一秒就用dp的方式构造,这个dp非常好写。
然后注意状态矩阵和转移矩阵要分清
#include
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std;
const int MAXN = 50 + 10;
const int mod = 10000;
int n, m, st, en, K, nfish;
int g[MAXN][MAXN];
vector fish[MAXN];
struct Matrix
{
int n, m;
int c[MAXN][MAXN];
Matrix() { memset(c, 0, sizeof(c)); }
void init(int p) { n = m = p; }
Matrix operator * (const Matrix& a)
{
Matrix res;
res.n = n; res.m = a.m;
REP(i, 0, res.n)
REP(j, 0, res.m)
REP(k, 0, m)
{
res.c[i][j] += c[i][k] * a.c[k][j];
res.c[i][j] %= mod;
}
return res;
}
}A[15], ans;
Matrix power(Matrix a, int b)
{
Matrix res; res.init(n);
REP(i, 0, n) res.c[i][i] = 1;
for(; b; b >>= 1)
{
if(b & 1) res = res * a;
a = a * a;
}
return res;
}
void read()
{
scanf("%d%d%d%d%d", &n, &m, &st, &en, &K);
_for(i, 1, m)
{
int x, y; scanf("%d%d", &x, &y);
g[x][y] = g[y][x] = 1;
}
scanf("%d", &nfish);
REP(i, 0, nfish)
{
int x, y; scanf("%d", &x);
while(x--)
{
scanf("%d", &y);
fish[i].push_back(y);
}
}
}
void get_Matrix()
{
_for(i, 0, 12) A[i].init(n);
_for(t, 1, min(12, K))
{
int vis[MAXN] = {0};
REP(i, 0, nfish)
vis[fish[i][t % fish[i].size()]] = 1;
REP(i, 0, n) if(!vis[i])
REP(j, 0, n) if(g[i][j])
A[t].c[j][i]++;
}
}
void work()
{
ans.n = 1; ans.m = n;
ans.c[0][st] = 1;
Matrix t; t.init(n);
REP(i, 0, n) t.c[i][i] = 1;
if(K >= 12)
{
_for(i, 1, 12) t = t * A[i];
t = power(t, K / 12);
}
_for(i, 1, K % 12) t = t * A[i];
ans = ans * t;
printf("%d\n", ans.c[0][en]);
}
int main()
{
read();
get_Matrix();
work();
return 0;
}