矩陣乘法:
Mat Mult(Mat a, Mat b){ // Mat 爲自定義類型
Mat c;
memset(c.m, 0, sizeof(c.m));
c.r= a.r; c.c=b.c; // 新的矩陣的行列
for(int i=0; i<=c.r; i++){
for(int j=0; j<=c.c; j++){
for(int k=0; k<=a.c; k++)
c.m[i][j]= (c.m[i][j]+a.m[i][k]*b.m[k][j]);
}
}
return c;
}
快速冪:
Mat Calc(int x){
if(x==1) {
return yuan; // 原始矩陣
}
Mat ret= Calc(x/2);
ret= Mult(ret, ret);
if(x%2==1) ret=Mult(ret, yuan);
return ret;
}
snack:
給定一個有向圖, 問在規定時間從起點出發沿邊行走並收集所有物品(邊上有一定的物品,收集花費時間2,否則花費時間1)的總方案數。
時間 10^9, 物品4, 頂點數爲25
考慮DP: f[i, j, k](i 所在頂點, j 經過時間, k收集物品的狀態) = { f[v, j-1, k] }+ { f[v, j-2, x] } 分別爲收集該邊和不收集改邊, 由於時間一維巨大, 考慮使用矩陣乘法。
定義一維矩陣G= {sum, f1, f2, f3 …, fn , g1, g2, g3, … gn} 爲到頂點1的總方案數, 時間i的每個頂點的每種狀態, i-1時間的頂點與狀態。
於是可以構造一個二位矩陣M { 符合上面的運算的 }
分析時間複雜度 25* 16 * 2+ 1= 801 O(N^3)的時間複雜度接受不了。
所以可以考慮容斥原理: 把ABCD含都加進方案裏,再把ABC, ABD, ACD , BCD減去 ……
這樣構造矩陣的時候比較和諧, 時間複雜度也變成了 O(16 * (25*2+1)^3 * log2(10^9) )
代碼:
#include<cstdio>
#include<cstring>
using namespace std;
#define N 25
#define M 51
#define Edge 500
#define Mod 5557
struct Mat{ int m[M][M], r , c ;};
const int data[16]={1, -1, -1 , 1, -1, 1, 1,-1, -1, 1, 1, -1, 1, -1, -1, 1};
Mat yuan, I;
int n,m,T;
int state[Edge], x[Edge], y[Edge];
int Change(char c){
if (c=='B') return 1; if (c=='J') return 2;
if (c=='M') return 4; if (c=='P') return 8;
}
void Make_State(int &s){
char c; while(c=getchar(), c<'A' || c>'Z');
s=Change(c); while(c=getchar(), c>='A'&& c<='Z') s+=Change(c);
}
void Init(){
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
scanf("%d%d",&x[i],&y[i]);
Make_State(state[i]);
}
scanf("%d",&T);
}
Mat Mult(Mat a, Mat b){
Mat c;
memset(c.m, 0, sizeof(c.m));
c.r= a.r; c.c=b.c;
for(int i=0; i<=c.r; i++){
for(int j=0; j<=c.c; j++){
for(int k=0; k<=a.c; k++)
c.m[i][j]= (c.m[i][j]+a.m[i][k]*b.m[k][j]) % Mod;
}
}
return c;
}
Mat Calc(int x){
if(x==1) {
return yuan;
}
Mat ret= Calc(x/2);
ret= Mult(ret, ret);
if(x%2==1) ret=Mult(ret, yuan);
return ret;
}
void mat(int S){
memset(yuan.m, 0, sizeof(yuan.m));
yuan.r=yuan.c=2*n;
yuan.m[0][0]= yuan.m[0][1]=1;
for(int i=1; i<=n; i++){yuan.m[n+i][i]=1;}
for(int i=0; i<m; i++){
int u=x[i], v=y[i];
yuan.m[v][u] =1;
if((state[i] | S)==S) yuan.m[v][u+n] =1;
}
}
int Solve(){
Mat amat=Calc(T+1);
memset(I.m, 0, sizeof(I.m));
I.r=n*2, I.c=0, I.m[0][0]=0; I.m[1][0]=1;
Mat ans= Mult(amat, I);
return ans.m[0][0];
}
void Work(){
int Ans=0;
for(int i=0;i<=15;i++){
mat(15-i);
int tt=Solve();
Ans= (Ans+ data[i]*tt ) % Mod;
}
Ans= (Ans+Mod)%Mod;
printf("%d\n",Ans);
}
int main(){
Init();
Work();
return 0;
}