ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

BZOJ 2165 大楼

2021-07-01 20:03:05  阅读:201  来源: 互联网

标签:matrix int res 大楼 矩阵 times 2165 我们 BZOJ


BZOJ 2165 大楼

​ 题目连接:https://remmina.github.io/BZPRO/JudgeOnline/2165.html


​ 很明显,答案是具有单调性的。如果乘坐次数少了肯定不行,多了肯定行。我们第一反应一定是二分。但是这道题并不是二分。因为我们如果二分答案的话,那为什么不直接一步一步做上去,每做一次就检查一下答案是否满足,这样甚至时间复杂度是优于二分的。那么我们就想暴力,问题就变成了怎么加速暴力。答案具有单调性,而且需要我们去加速。显然倍增的优化就呼之欲出了。确定了基本想法。下面的问题就是怎么去倍增。

​ 由于我们可以到达 \(n\) 个房间,每做一次的决策也是多样化的。如果只是预处理 w[x] 数组表示从 1 开始走 \(2^x\) 步能到达的最高高度。我们发现,由于决策的多样化,我们并不好处理出这样的数组。注意到既然决策是多种多样的,我们何不将所有的决策都倍增出来?注意到 \(n\) 的值域并不大,只有 100。我们可以用矩阵来表示每一种决策所导致的结果。具体点说,我们让一个矩阵 v[i][j] 表示从 \(i\) 到 \(j\) 的最大权值。如果不能到达的话 v[i][j]=-1。我们设 w[i] 为一个矩阵他表示的是最多走\(2^i\)步所能产生的矩阵。转移式为:

\[w_i=w_{i-1}\times w_{i-1} \]

​ 乘法是什么意思,这里的乘法并不是真正矩阵的乘法,而是一种类似于 floyd 的思想。我们定义矩阵的乘法如下。

\[a\times b=res,res_{i,j}=\max(res_{i,j},a_{i,k}+b_{k,j})\;(1\le i,j,k\le n,a_{i,k}\not=-1,b_{k,j}\not=-1) \]

​ 上界问题,我们就一直做 \(w_i=w_{i-1}\times w_{i-1}\) 这个操作。直到 \(w_{i}\) 满足条件。(在本题中满足条件的矩形 \(v\) 有 \(max(v_{1,i})\ge m\;(1\le i\le n)\))然后我们运用 倍增LCA 的思想,从大到小枚举 \(i\)。如果目前的矩阵 \(tmp\times w_i\) 不满足条件,我们就让 \(tmp\) 乘上一个 \(w_i\)。然后 \(ans\) 加上一个 \(2^i\)。最后再让 \(ans+1\)。总的来说,时间复杂度为 \(O(n^3\times up)\)。\(up\) 表示上界,最大不会超过 \(\log_2(10^{18})\) 。详情见代码。

代码如下:

#include<bits/stdc++.h>
#define ll long long
#define R register
using namespace std;
const int MAXN = 105;
int n;
ll m;
struct matrix
{
    ll v[MAXN][MAXN];
    matrix()
    {
        memset(v,-1,sizeof v);
    }
    matrix operator *(const matrix &x)
    {
        matrix ans;
        for(R int k=1;k<=n;++k) for(R int i=1;i<=n;++i) for(R int j=1;j<=n;++j)
            if(v[i][k]!=-1&&x.v[k][j]!=-1)
                ans.v[i][j]=max(v[i][k]+x.v[k][j],ans.v[i][j]);
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                ans.v[i][j]=min(m,max(ans.v[i][j],max(v[i][j],x.v[i][j])));
        return ans;
    }
}w[61];
bool judge(matrix a)
{
    for(R int i=1;i<=n;++i)
        if(a.v[1][i]>=m) return true;
    return false;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %lld",&n,&m);
        for(R int i=1;i<=n;++i)
            for(R int j=1;j<=n;++j)
            {
                scanf("%lld",&w[0].v[i][j]);
                if(!w[0].v[i][j]) w[0].v[i][j]=-1;
            }
        ll up=1,ans=0;
        for(int i=1;;++i,++up)
        {
            w[i]=w[i-1]*w[i-1];
            if(judge(w[i])) break;
        }
        for(R int i=1;i<=up;++i)
            w[i]=w[i-1]*w[i-1];
        bool flag=0;matrix tmp;
        for(int i=up;i>=0;--i)
        {
            matrix res;
            if(flag) res=tmp*w[i];
            else res=w[i];
            if(!judge(res))
            {
                tmp=res;
                flag=1;
                ans+=(1ll<<(ll)(i));
            }
        }
        printf("%lld\n",ans+1);
    }
    return 0;
}

文末提一嘴,校内OJ上卡常,所以这个代码跑了4400ms(4000ms为AC),只有80分,理论上是能过的,所以在OJ上开了O2。不开O2的代码在这份的基础上卡卡常就能过,我比较懒所以开了O2

标签:matrix,int,res,大楼,矩阵,times,2165,我们,BZOJ
来源: https://www.cnblogs.com/nightsky05/p/14960482.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有