【TOJ 2871】Magic Bean【DP+矩陣快速冪】

題意:給出一個無向圖,有一個bean開始在1號節點上。每一秒中它可以跳到相接的點上,或者停在原處,它時刻都可能爆炸,問在t秒內,它有多少種行爲數目。


思路:dp,定義dp[i][j][1]表示i秒的時刻停在j上,並且沒有爆炸的方案數目。dp[i][j][0]表示i秒停在j上的方案數目(包括爆炸了)。

            狀態轉移方程爲:dp[i][j][0] = dp[i-1][j][0]+dp[i-1][j][1]+dp[i-1][k][1], dp[i][j][1] = dp[i-1][j][1]+dp[i-1][k][1](k表示與j相鄰的點),由於這裏t<10^6,所以必須用矩陣快速冪進行加速。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
#define mod 2007
#define N 42

inline void add(int &i, int j) {
    i += j;
    if (i >= mod) i -= mod;
}

int n;

struct M{
    int v[N][N];
    M operator*(M a) const{
        int i, j, k;
        M tm;
        memset(tm.v, 0, sizeof(tm.v));
        int m = (n<<1);
        for (i = 0;i < m;i++) {
            for (j = 0;j < m;j++) {
                for (k = 0;k < m;k++)
                    add(tm.v[i][j], v[i][k]*a.v[k][j]%mod);
            }
        }
        return tm;
    }
}E, A;

bool vis[N][N];
int dp[N];

M cal(M a, int b) {
    M tm = E;
    while (b) {
        if (b&1) tm = tm*a;
        a = a*a, b>>=1;
    }
    return tm;
}

void init() {
    int i, j, l, y;
    memset(A.v, 0, sizeof(A.v));
    memset(dp, 0, sizeof(dp));
    for (i = 1;i <= n;i++) {
        l = i*2-2, y = l+1;
        A.v[l][l] = A.v[y][l] = 1;
        A.v[y][y] = 1;
        for (j = 1;j <= n;j++) {
            if (!vis[i][j]) continue;
            A.v[2*j-1][l] = A.v[2*j-1][y] = 1;
        }
    }
    dp[0] = dp[1] = 1;
}

int main() {
    int m, i, j, u, v, t, k;
    for (i = 0;i < N;i++) E.v[i][i] = 1;
    while (scanf("%d%d", &n, &m), n||m) {
        memset(vis, false, sizeof(vis));
        for (i = 0;i < m;i++) {
            scanf("%d%d", &u, &v);
            if (vis[u][v]) continue;
            vis[u][v] = vis[v][u] = true;
        }
        init();
        scanf("%d", &t);
        A = cal(A, t);
        int tm, ans = 0;
        for (i = 1;i <= n;i++) {
            tm = 0;
            for (k = 0;k < 2*n;k++) {
                add(tm, dp[k]*A.v[k][2*i-2]%mod);
            }
            add(ans, tm);
        }
        printf("%d\n", ans);
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章