hdu 5411 CRB and Puzzle(矩阵快速幂)

题意:

给一个有向图,从任意点开始,最多走m步,求形成的图案总数。

思路:

dp[i][j] 表示:走 j 步最后到达i的方法数,
dp[i][j]=dp[k][j1] ,其中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=DM1[i][j] (1in+11jn+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;
}

你可能感兴趣的:(HDU,5411)