bzoj2165 大楼 floyd+倍增

24 篇文章 0 订阅

Description


xz是一个旅游爱好者,这次他来到了一座新的城市。城市中央有一幢高耸入云的大楼。这幢楼到底有多少层呢?据说和非负整数的个数是一样多的。xz想爬上这座大楼来观赏新城市的全景。这幢大楼的楼层从下至上用从小到大的非负整数编号。每层楼有n个房间,用1到n的正整数编号。楼层之间用电梯连接,电梯只能上行,不能下行或者同层移动。(下楼一般自行解决)电梯用(u,v,w)的形式给出,表示对于任意正整数i,有第i层的房间u到第i+w层的房间v有一部电梯。电梯只能从起点开往终点,不能中途停留。 xz想要观赏城市全景,至少需要登上第m层楼,即最终需要到达的楼层数≥m。由于乘坐电梯要缴纳高额的费用,而如果花销太大回家就没法报账了,xz希望乘坐电梯的次数最少。现在xz在第0层的1号房间,你需要求出这个最少的乘坐次数。

有10%的数据所有的n=2
有20%的数据m≤3000
有20%的数据对于满足1≤i,j≤n的整数i和j,若wi,j≠0,则有wi,j≥10^15
有30%的数据所有的n=40
以上各类数据均不包含其他类数据

对于所有数据T=5,1≤n≤100,1≤m≤10^18
对于满足1≤i,j≤n的整数i和j,有0≤wi,j≤10^18。数据保证能够到达m层或更高的楼层。

Solution


比较容易想到f[k][i][j]表示从i到j走了i^k步后上升的最高楼层数,这个类似floyd一下就搞出来了
然后就可以愉快的倍增了

本人非常zz地选取了2^31作为INF的取值,显然这在LL题里是不太现实的

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>

#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define copy(x,t) memcpy(x,t,sizeof(x))

typedef long long LL;
const LL INF=1e18;
const int N=205;

LL f[65][N][N],rec[N],tmp[N];

LL read() {
    LL x=0,v=1; char ch=getchar();
    for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
    for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
    return x*v;
}

int main(void) {
    freopen("data.in","r",stdin);
    freopen("myp.out","w",stdout);
    for (int T=read();T--;) {
        int n=read(),r=0; LL m=read();
        LL ans=0;
        rep(i,1,n) rep(j,1,n) {
            f[0][i][j]=read();
            f[0][i][j]=(!f[0][i][j])?-INF:f[0][i][j];
        }
        rep(w,1,60) {
            rep(i,1,n) rep(j,1,n) {
                f[w][i][j]=-INF;
                rep(k,1,n) f[w][i][j]=std:: max(f[w][i][j],f[w-1][i][k]+f[w-1][k][j]);
            }
            bool flag=false;
            rep(i,1,n) if (f[w][1][i]>=m) {
                flag=true; break;
            }
            if (flag) {
                r=w; break;
            }
        }
        rep(i,1,n) rec[i]=f[r-1][1][i];
        ans+=(LL)(1LL<<(r-1));
        drp(w,r-2,0) {
            rep(i,1,n) { tmp[i]=-INF;
                rep(j,1,n) {
                    tmp[i]=std:: max(tmp[i],rec[j]+f[w][j][i]);
                }
            }
            bool flag=true;
            rep(i,1,n) if (tmp[i]>=m) flag=false;
            if (flag) {
                copy(rec,tmp);
                ans+=(LL)(1LL<<w);
            }
        }
        printf("%lld\n", ans+1);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值