【BZOJ】2165: 大楼

【BZOJ】2165: 大楼

【题意】从第0层开始有无穷层,每层有n个房间,给定矩阵A,A[i][j]表示从第x层的房间 i 可以跳到第x+A[i][j]层的房间 j (x任意),A[i][j]=0表示不能跳。初始在第0层第1个房间,求最少跳几次可以到达>=m层。n<=100,m<=10^18。

【算法】矩阵快速幂

【题解】我的写法好像和网上的不太一样……

设$f_n[i]$表示跳n步在房间 i 的最高层数(这里全部的n和题目的n无关),考虑递推列向量$f_n$,设转移矩阵T,满足$T_{i,j}=A_{j,i}$,那么有:

$$T \times f_n=f_{n+1}$$

初始状态f0={1,0,0…0},那么写成幂形式:

$$T^n \times f_0=f_n$$

为了方便,容易发现$T^n$的最左一列就是$f_n$。

我们要跳到$f_n$中包含>=m的数字为止,所以预处理所有$T^{2^i}$,倍增即可。

复杂度O(n^3*log m+n log m)。

【BZOJ】2165: 大楼
【BZOJ】2165: 大楼

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=101;
const ll inf=1000000000000000000;
ll m,c2[N],c[N][N],A[70][N][N],ans[N][N],ans2[N][N];
int n;
void multply(ll a[N][N],ll b[N][N],ll d[N][N]){
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            c[i][j]=-inf;//
            for(int k=1;k<=n;k++){
                c[i][j]=max(c[i][j],a[i][k]+b[k][j]);
            }
        }
    }
    for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)d[i][j]=c[i][j];
}
int main(){
    int T;scanf("%d",&T);
    while(T--){
        scanf("%d%lld",&n,&m);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                scanf("%lld",&A[0][j][i]);
                if(A[0][j][i]==0)A[0][j][i]=-inf;
            }
        }
        int tot=0;
        bool ok=0;
        for(int i=1;i<=n;i++)if(A[tot][i][1]>=m){ok=1;break;}
        if(!ok){
            while(1){
                tot++;
                multply(A[tot-1],A[tot-1],A[tot]);
                bool ok=0;
                for(int i=1;i<=n;i++)if(A[tot][i][1]>=m){ok=1;break;}
                if(ok)break;
            }
        }
        c2[0]=1;
        for(int i=1;i<=tot-1;i++)c2[i]=c2[i-1]*2;
        ll ANS=c2[tot-1];
        for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)ans[i][j]=A[tot-1][i][j];
        for(int i=tot-2;i>=0;i--){
            multply(ans,A[i],ans2);
            bool ok=1;
            for(int j=1;j<=n;j++)if(ans2[j][1]>=m)ok=0;
            if(ok){
                ANS+=c2[i];
                for(int k=1;k<=n;k++)for(int l=1;l<=n;l++)ans[k][l]=ans2[k][l];//
            }
        }
        printf("%lld\n",ANS+1);
    }
    return 0;
}

View Code

 

注意T[i][j]=0时设为-inf,即不可达。

 

网上的角度:关键在于题意的理解……给定n个点的有向图边权矩阵,0表示无边,求最少经过几条边使得路径长度>=m。

经过指定条边后的最长路矩阵是很容易知道的,设$C^x$表示经过x条边后的最长路矩阵,$A$表示有向边权矩阵(0要设为-inf),那么:

$$C^x(i,j)=\max_k\{C^{x-1}(i,k)+A(k,j)\}$$

所以C^x=A^x。

预处理$C^{2^i}$,然后倍增到第一行出现>=m的数字为止。

复杂度O(n^3 log m+n log m)。

 

转载于:https://www.cnblogs.com/onioncyc/p/8780568.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/101723.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • php 第三方登录总结OAuth协议

    php 第三方登录总结OAuth协议

    2021年10月25日
    60
  • protel99SE – 多张原理图生成一张总网表的方法

    protel99SE – 多张原理图生成一张总网表的方法protel99SE-多张原理图生成一张总网表的方法1.新建一张原理图,点击”PlaceSheetSymbol”放置一个原理图符号,然后右击选其“proterties”,在filename    一栏输入你准备与之绑定的原理图文件名.确定ok.  依此类推…,直到把全部的原理图与每一个放置的原理图符号绑定完为止。最后保存。2.打开全部的原理图(否则导入PCB时不

    2022年5月22日
    49
  • SpringBoot配置Mybatis:详细易懂「建议收藏」

    SpringBoot配置Mybatis:详细易懂「建议收藏」文章目录SpringBoot配置Mybatis:详细易懂前期准备工作Mybatis相应配置编写相应代码文件结构和结果增删查改Mybatis动态SQL参考文章SpringBoot配置Mybatis:详细易懂Mybatis作为后端持久层框架,在互联网大厂中应用广泛,所以掌握Mybatis,可谓是必备的。最近准备系统得复习一下Mybatis框架,所以博客会更几期关于Mybatis得文章,如果觉得…

    2022年6月24日
    43
  • 内存对齐宏的定义

    内存对齐宏的定义

    2021年8月20日
    49
  • Word 在试图打开文件时遇到错误 解决办法

    Word 在试图打开文件时遇到错误 解决办法Word在试图打开文件时遇到错误,通过属性设置解除锁定可解决。

    2022年4月29日
    79
  • 二维数组赋值 java_java二维数组的赋值方法「建议收藏」

    二维数组赋值 java_java二维数组的赋值方法「建议收藏」在java数组中,我们想要知道其长度,可以通过赋值的方法来实现。在正式开始对数组赋值前,我们要明确其中的下标问题。在准备步骤上,先找到高维的位置,再确定低纬的下标,就可以进行相关的赋值操作了。下面就具体的二维数组赋值,我们先简单分析赋值的概念,然后带来具体的赋值实例。1.赋值概念使用双下标访问二维数组中的元素:第一个下标代表:行号(高维下标)。第二个下标代表:列号(低维下标)。2.赋值实例(1)赋…

    2022年5月6日
    159

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号