现在的位置: 首页 > 综合 > 正文

BZOJ 1875 SDOI 2009 HH去散步 矩阵乘法优化DP

2018年01月19日 ⁄ 综合 ⁄ 共 1159字 ⁄ 字号 评论关闭

题目大意:给出一张无向图,求从A到B走k步(不能走回头路)的方案数。(k <= 2^30)

思路:看到k的范围就知道是矩阵乘法了。关键是不能走回头路怎么构造。正常的方法构造点的转移不能避免这个问题,就用边来构造。只要保证不经过自己^1的边就可以保证不走回头路了。

CODE:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 210
#define MO 45989
using namespace std;
 
int total = 1;
 
struct Matrix{
    int num[MAX][MAX];
     
    Matrix() {
        memset(num,0,sizeof(num));
    }
    Matrix operator *(const Matrix &a)const {
        Matrix re;
        for(int i = 0; i <= total; ++i)
            for(int j = 0; j <= total; ++j)
                for(int k = 0; k <= total; ++k) {
                    re.num[i][j] += num[i][k] * a.num[k][j];
                    re.num[i][j] %= MO;
                }
        return re;
    }
}src,ans,temp;
 
int points,edges,t;
int S,T;
int head[MAX];
int next[MAX],aim[MAX];
 
inline void Add(int x,int y)
{
    next[++total] = head[x];
    aim[total] = y;
    head[x] = total;
}
 
int stack[MAX],top;
 
int main()
{
    cin >> points >> edges >> t >> S >> T;
    ++S,++T;
    for(int x,y,i = 1; i <= edges; ++i) {
        scanf("%d%d",&x,&y);
        x++,y++;
        Add(x,y),Add(y,x);
    }
    for(int i = head[S]; i; i = next[i])
        ans.num[0][i] = 1;
    for(int i = 2; i <= total; ++i) {
        int x = aim[i];
        if(x == T)  stack[++top] = i;
        for(int j = head[x]; j; j = next[j]) {
            if(j == (i^1))  continue;
            src.num[i][j] = 1;
        }
    }
    for(int i = 0; i <= total; ++i)  temp.num[i][i] = 1;
    --t;
    while(t) {
        if(t&1) temp = temp * src;
        src = src * src;
        t >>= 1;
    }
    ans = ans * temp;
    int p = 0;
    for(int i = 1; i <= top; ++i)
        p = (p + ans.num[0][stack[i]]) % MO;
    cout << p << endl;
    return 0;
}

抱歉!评论已关闭.