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;
}
时间: 2024-10-11 11:10:43

BZOJ 1898 ZJOI 2004 Swamp 沼泽鳄鱼 矩阵乘法的相关文章

BZOJ 1898: [Zjoi2005]Swamp 沼泽鳄鱼 [矩阵乘法]

1898: [Zjoi2005]Swamp 沼泽鳄鱼 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1082  Solved: 602[Submit][Status][Discuss] Description 潘塔纳尔沼泽地号称世界上最大的一块湿地,它地位于巴西中部马托格罗索州的南部地区.每当雨季来临,这里碧波荡漾.生机盎然,引来不少游客.为了让游玩更有情趣,人们在池塘的中央建设了几座石墩和石桥,每座石桥连接着两座石墩,且每两座石墩之间至多只有一座石

【BZOJ1898】[Zjoi2005]Swamp 沼泽鳄鱼 矩阵乘法

[BZOJ1898][Zjoi2005]Swamp 沼泽鳄鱼 Description 潘塔纳尔沼泽地号称世界上最大的一块湿地,它地位于巴西中部马托格罗索州的南部地区.每当雨季来临,这里碧波荡漾.生机盎然,引来不少游客.为了让游玩更有情趣,人们在池塘的中央建设了几座石墩和石桥,每座石桥连接着两座石墩,且每两座石墩之间至多只有一座石桥.这个景点造好之后一直没敢对外开放,原因是池塘里有不少危险的食人鱼.豆豆先生酷爱冒险,他一听说这个消息,立马赶到了池塘,想做第一个在桥上旅游的人.虽说豆豆爱冒险,但也不

【BZOJ1898】【Zjoi2004】Swamp 沼泽鳄鱼 矩阵乘法

广告: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/44101165"); } 题解: 食人鱼循环2.3.4,lcm=12. 所以12次转移为一组,这么进行快速幂矩乘,最后把余数那几次转移乘上. 代码: #include <cstdio> #include <cstri

[BZOJ 2326] [HNOI2011] 数学作业 【矩阵乘法】

题目链接:BZOJ - 2326 题目分析 数据范围达到了 10^18 ,显然需要矩阵乘法了! 可以发现,向数字尾部添加一个数字 x 的过程就是 Num = Num * 10^k + x .其中 k 是 x 的位数. 那么位数相同的数字用矩阵乘法处理就可以了. [Num, x, 1] * [10^k, 0, 0] = [Num*10^k+x, x+1, 1] [      1, 0, 0] [      0, 1, 1] 枚举位数,做多次矩阵乘法. 其中两个整数相乘可能会爆 LL ,那么就用类似

BZOJ 4870 [Shoi2017]组合数问题 ——动态规划 矩阵乘法

注意到$r<k$ 别问我为什么要强调. 考场上前30分水水. 然后写阶乘的时候大力$n\log {n}$预处理 本机跑的挺快的,然后稳稳的T掉了. 然后就是简单的矩阵乘法了. #include <map> #include <cmath> #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm

BZOJ 2326 HNOI 2011 数学作业 矩阵乘法

题目大意 求一个这样的数:"12345678910111213--"对m取模的值. 思路 观察这个数字的特点,每次向后面添加一个数.也就是原来的数乘10^k之后在加上一个数.而且处理每个数量级的时候是相似的.所以就可以用矩阵乘法来加速.我构造的矩阵是这样的. [当前数字累加数字1]×???数量级10011001???=[新的数字累加数字+11] CODE #include <cstdio> #include <cstring> #include <iost

bzoj 1875: [SDOI2009]HH去散步 -- 矩阵乘法

1875: [SDOI2009]HH去散步 Time Limit: 20 Sec  Memory Limit: 64 MB Description HH有个一成不变的习惯,喜欢饭后百步走.所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离. 但 是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走回. 又因为HH是个喜欢变化的人,所以他每 天走过的路径都不完全一样,他想知道他究竟有多 少种散步的方法. 现在给你学校的地图(假设每条路的长度都 是一样的都是1),问长度为t,从给定

bzoj 3231: [Sdoi2008]递归数列【矩阵乘法】

今天真是莫名石乐志 一眼矩阵乘法,但是这个矩阵的建立还是挺有意思的,就是把sum再开一列,建成大概这样 然后记!得!开!long!long!! #include<iostream> #include<cstdio> using namespace std; const int N=20; long long n,b[N],c[N],sum,l,r,mod; struct jz { long long a[N][N]; jz operator * (const jz &b)

BZOJ 2553 BeiJing2011 禁忌 AC自动机+矩阵乘法

题目大意:给定n个模式串,定义一个字符串的伤害为所有子串的划分中最多包含的模式串数量,求长度为len的字符串的伤害期望值 小五prpr,恋恋prpr,大小姐prpr 首先建立AC自动机 令f[i][j]表示长度为i的字符串在AC自动机上的第j个节点的伤害期望值 如果要走到某个节点是危险节点或者fail指针指向危险节点,就ans++,然后回到根节点 这样构造出来的矩阵做快速幂= = 这么做都会把- - 不会别骂我- - 但是跑完发现找不到答案- - 因此我们需要稍微改造一下- - 新建一个节点 如