题意:
给一个有向图,从任意点开始,最多走m步,求形成的图案总数。
思路:
令 dp[i][j] 表示:走 j 步最后到达i的方法数,
则dp[i][j]=∑dp[k][j−1] ,其中k表示:走 j 步可以直接到达i 的点。
ans=∑dp[i][j] 。
此题的关键在于,如何减少状态转移的时间,考虑用矩阵加速。
D=⎛⎝⎜⎜⎜⎜⎜⎜a[1][1]a[2][1]a[3][1]......a[1][2]a[2][2].........a[1][3]........................a[n][n]11111⎞⎠⎟⎟⎟⎟⎟⎟
其中a[i][j]表示有向图,用于状态转移,右边的一列1用于累加答案。
ans=∑∑DM−1[i][j] (1≤i≤n+1,1≤j≤n+1)
my code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef __int64 ll;
const int INF = 0x3f3f3f3f;
const ll MOD = 2015;
const int SIZE = 105;
int size;
int n, m;
struct Matrix {
ll v[SIZE][SIZE];
Matrix() { memset(v, 0, sizeof(v)); }
};
Matrix operator * (Matrix a, Matrix b) {
Matrix c;
for(int i = 0; i < size; i++) {
for(int j = 0; j < size; j++) {
c.v[i][j] = 0;
for(int k = 0; k < size; k++) {
c.v[i][j] += (a.v[i][k] * b.v[k][j]) % MOD;
c.v[i][j] %= MOD;
}
}
}
return c;
}
Matrix operator ^ (Matrix a, ll k) {
Matrix c;
for(int i = 0; i < size; i++) {
c.v[i][i] = 1;
}
while(k) {
if(k & 1) c = a * c;
a = a * a;
k >>= 1;
}
return c;
}
int main() {
int k, x;
int T;
scanf("%d", &T);
while(T--) {
Matrix A;
scanf("%d%d", &n, &m);
size = n+1;
for(int i = 0; i < n; i++) {
scanf("%d", &k);
for(int j = 0; j < k; j++) {
scanf("%d", &x);
A.v[i][x-1] = 1;
}
}
for(int i = 0; i < size; i++)
A.v[i][size-1] = 1;
if(m == 0) {
puts("1");
continue;
}
Matrix ret = A^(m-1);
ll ans = 0;
for(int i = 0; i < size; i++) {
for(int j = 0; j < size; j++) {
ans = (ans + ret.v[i][j]) % MOD;
}
}
printf("%I64d\n", ans);
}
return 0;
}