BZOJ 1898 ZJOI 2004 Swamp 沼泽鳄鱼 矩阵乘法

题目大意

给出一张无向图,这个图中有一些鱼,他们不同的时间会出现在固定的位置,呈周期性循环,一个人要在这个图上走,他不能和鱼同时在一个点上。问从s到t走k步有多少种方案。

思路

注意到鱼的循环只可能是2/3/4,也就是说最多经过12个时间点之后,状态又会和一开始相同。所以预处理12个矩阵用来转移。分为k/12和k%12来处理。
当鱼在一个位置上的时候,当前时间从这个位置出发的一行和上一个时间到达这个点的一列需要清零。

CODE

#define _CRT_SECURE_NO_WARNINGS

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 60
#define MO 10000
using namespace std;

int points;

struct Matrix{
    int num[MAX][MAX];
    int w,h;

    Matrix(int _,int __):w(_),h(__) {
        memset(num,0,sizeof(num));
    }
    Matrix() {
        memset(num,0,sizeof(num));
    }
    Matrix operator *(const Matrix &a)const {
        Matrix re(w,a.h);
        for(int i = 1; i <= w; ++i)
            for(int j = 1; j <= a.h; ++j) {
                for(int k = 1; k <= h; ++k)
                    re.num[i][j] += num[i][k] * a.num[k][j];
                re.num[i][j] %= MO;
            }
        return re;
    }
    void ClearHor(int line) {
        for(int i = 1; i <= points; ++i)
            num[line][i] = 0;
    }
    void ClearVer(int line) {
        for(int i = 1; i <= points; ++i)
            num[i][line] = 0;
    }
}src[20];

struct Fish{
    int cnt,num[10];

    void Read() {
        scanf("%d",&cnt);
        for(int i = 0; i < cnt; ++i)
            scanf("%d",&num[i]),++num[i];
    }
}fish[MAX];

int edges,s,t;
long long k;
int fishes;

Matrix QuickPower(Matrix a,long long y)
{
    Matrix re(points,points);
    for(int i = 1; i <= points; ++i)
        re.num[i][i] = 1;
    while(y) {
        if(y&1) re = re * a;
        a = a * a;
        y >>= 1;
    }
    return re;
}

int main()
{
    cin >> points >> edges >> s >> t >> k;
    ++s,++t;
    Matrix map(points,points);
    for(int x,y,i = 1; i <= edges; ++i) {
        scanf("%d%d",&x,&y);
        ++x,++y;
        map.num[x][y] = map.num[y][x] = 1;
    }
    for(int i = 0; i < 12; ++i)
        src[i] = map;
    cin >> fishes;
    for(int i = 1; i <= fishes; ++i)
        fish[i].Read();
    for(int i = 0; i < 12; ++i) {
        for(int j = 1; j <= fishes; ++j) {
            int pos = fish[j].num[i % fish[j].cnt];
            if(i)   
                src[i - 1].ClearVer(pos);
            src[i].ClearHor(pos);
        }
    }
    Matrix base(points,points);
    for(int i = 1; i <= points; ++i)
        base.num[i][i] = 1;
    for(int i = 0; i < 12; ++i)
        base = base * src[i];
    Matrix ans = QuickPower(base,k / 12);
    k %= 12;
    for(int i = 0; i < k; ++i)
        ans = ans * src[i];
    cout << ans.num[s][t] << endl;
    return 0;
}

你可能感兴趣的:(矩阵乘法,bzoj,ZJOI2014)