[BZOJ1898][Zjoi2005]Swamp 沼泽鳄鱼(dp+矩阵优化)

本文介绍了如何解决[BZOJ1898][Zjoi2005]Swamp(沼泽鳄鱼)问题,采用动态规划(dp)和矩阵优化的方法。通过构建状态f(i,j)表示在时间i到达位置j的方案数,并处理鳄鱼出现的情况,优化时间复杂度。由于鳄鱼周期特性,利用矩阵乘法将转移矩阵预先计算,再用快速幂处理,最后结合剩余次数完成转移。遗憾的是,作者在实现过程中遇到了long long类型不支持位运算的问题,导致未能正确运行。" 112728635,10535532,Python开发串口通讯上位机:批量上传图片到MySQL入门,"['Python开发', '串口通讯', '上位机编程', '数据传输', '数据库交互']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

传送门

题解

f(i,j)表示时间为i时到达j的方案数,答案即为f(k,t)
condi(i,j)表示时间为i时j有没有鳄鱼0/1
那么 f(i,j)=(v,j)Ef(i1,v)
并且当condi(i,j)=1时f(i,j)=0
时间复杂度 O(kn2) ,考虑怎么优化
因为鳄鱼的周期只可能是234,所以f的转移是以12为周期循环的
那么我们可以把这12次转移用矩阵处理出来,由于矩阵满足结合律,可以先将它们乘起来然后快速幂k/12次,最后在乘上剩余的
矩阵的构造方法就是一个n*n的矩阵,如果f(i-1,j)可以转移到f(i,v),那么在a[j,v]置1

ljw学姐的测试题,完完全全想出来了正解,然而被埋在了一个奇怪的地方——long long不能做位运算!
GG

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define N 55
#define Mod 10000

int n,m,s,t,k,x,y,nfish;
int T[N],p[N][5];
bool condi[N][N],flag[N][N];
struct data{int a[N][N];}unit,st,A,trans[N],ans;

data cheng(data a,data b)
{
    data ans;memset(ans.a,0,sizeof(ans.a));
    for (int k=1;k<=n;++k)
        for (int i=1;i<=n;++i)
            for (int j=1;j<=n;++j)
                ans.a[i][j]=(ans.a[i][j]+a.a[i][k]*b.a[k][j])%Mod;
    return ans;
}
data fast_pow(data a,int p)
{
    data ans=unit;
    for (;p;p>>=1,a=cheng(a,a))
        if (p&1)
            ans=cheng(ans,a);
    return ans;
}
int main()
{
    scanf("%d%d%d%d%d",&n,&m,&s,&t,&k);++s,++t;
    for (int i=1;i<=m;++i)
    {
        scanf("%d%d",&x,&y);++x,++y;
        flag[x][y]=flag[y][x]=1;
    }
    scanf("%d",&nfish);
    for (int i=1;i<=nfish;++i)
    {
        scanf("%d",&T[i]);
        for (int j=1;j<=T[i];++j) scanf("%d",&p[i][j]),++p[i][j];
    }
    for (int i=1;i<=min(k,12);++i)
        for (int j=1;j<=nfish;++j)
        {
            int now=p[j][i%T[j]+1];
            condi[i][now]=1;
        }

    for (int i=1;i<=n;++i) unit.a[i][i]=1;
    st.a[1][s]=1;

    for (int i=1;i<=min(k,12);++i)
    {
        for (int j=1;j<=n;++j)
            if (!condi[i][j])
                for (int l=1;l<=n;++l)
                    if (flag[l][j])
                        trans[i].a[l][j]=1;
    }
    A=unit;
    for (int i=1;i<=min(k,12);++i)
        A=cheng(A,trans[i]);
    if (k>12)
    {
        A=fast_pow(A,k/12);
        for (int i=1;i<=k%12;++i)
            A=cheng(A,trans[i]);
    }
    ans=cheng(st,A);
    printf("%d\n",ans.a[1][t]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值