HDOJ 2254 - 奥运

Matrix Multiplication (& Quick Power) 


Description

求v1到v2两个点之间,长度为t1~t2的路径总数。


Type

Matrix Multiplication

Quick Power


Analysis

这题可以用传递闭包的思想。

即这张图邻接矩阵的n次幂,即为两点之间长度为n的路径总数。

然后矩阵乘法+快速幂求解。

但是这道题有几个要注意的:

  • 题目中城市的总数小于30,这保证了我们构造的矩阵不会太大。

但是输入中的城市p1、p2的取值范围是int的范围。

因此我们要用一个map,把城市映射到0~30的点上。

  • 这题的数据规模较大,在计算t1~t2路径总数时,不能对[t1, t2]中的每一点都做矩阵乘法+快速幂,否则会TLE。

正确方法应该是,计算出指数为t1时的邻接矩阵,然后指数递增到t2,其中对所求的路径求和。

  • 注意t1 = 0的情况,这时候路径数应该为0。

Solution

// HDOJ 2254
// 奥运
// by A Code Rabbit

#include <cstdio>
#include <cstring>
#include <map>
using namespace std;

const int MAXO = 32;
const int MOD = 2008;

template <typename T>
struct Matrix {
    T e[MAXO][MAXO];
    int o;
    Matrix(int ord) { memset(e, 0, sizeof(e)); o = ord; }
    Matrix operator*(const Matrix& one) {
        Matrix res(o);
        for (int i = 0; i < o; i++)
            for (int j = 0; j < o; j++)
                for (int k = 0; k < o; k++)
                    res.e[i][j] += e[i][k] * one.e[k][j];
        return res;
    }
    Matrix operator%(int mod) {
        for (int i = 0; i < o; i++)
            for (int j = 0; j < o; j++)
                e[i][j] %= mod;
        return *this;
    }
};

template <typename T>
T QuickPower(T rdx, int exp, int mod) {
    T res = rdx;
    exp--;
    while (exp) {
        if (exp & 1) res = res * rdx % mod;
        exp >>= 1;
        rdx = rdx * rdx % mod;
    }
    return res;
}

int n;
int p1, p2;
int k;
int v1, v2, t1, t2;

map<int, int> city;
int tot_city;

int GetPos(int x);

int main() {
    while (scanf("%d", &n) != EOF) {
        // Input and count.
        city.clear();
        tot_city = 0;
        Matrix<int> mat_one(MAXO);
        for (int i = 0; i < n; i++) {
            scanf("%d%d", &p1, &p2);
            int pos1 = GetPos(p1); int pos2 = GetPos(p2);
            mat_one.e[pos1][pos2]++;
        }
        mat_one.o = tot_city;
        // Input, run and output.
        scanf("%d", &k);
        for (int i = 0; i < k; i++) {
            scanf("%d%d%d%d", &v1, &v2, &t1, &t2);
            if (city.find(v1) == city.end() || city.find(v2) == city.end()) {
                printf("0\n");
                continue;
            }
            Matrix<int> mat_ans(tot_city);
            if (t1) {
                mat_ans = QuickPower(mat_one, t1, MOD);
            } else {
                for (int i = 0; i < mat_ans.o; i++)
                    mat_ans.e[i][i] = 1;
            }
            int pos1 = city[v1]; int pos2 = city[v2];
            int sum = !t1 ? 0 : mat_ans.e[pos1][pos2];
            for (int j = t1 + 1; j <= t2; j++) {
                mat_ans = mat_ans * mat_one % MOD;
                sum += mat_ans.e[pos1][pos2];
            }
            printf("%d\n", sum % MOD);
        }
    }
    
    return 0;
}

int GetPos(int x) {
    if (city.find(x) == city.end())
        city[x] = tot_city++;
    return city[x];
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值