zoukankan      html  css  js  c++  java
  • bzoj 2165 DP

      首先如果不考虑数据范围的话,因为每一层都是等效的,所以我们可以用w[i][j][k]来表示在某一层的j位置,称作i次电梯到k位置,最多上升多少层,那么我们可以比较容易的写出转移,因为m十分大,i可能与m同阶,所以我们不能直接枚举i,这样我们考虑二进制的思想,w[2^p][j][k]表示用了2^p次电梯,最多上升的层数,那么这样我们可以直接由w[2^p-1][j][mid]和w[2^p-1][mid][k]转移过来,但是这样求出来的是我们最少用2^p次可以到达m层,最后的答案可能会比这个小,那么我们可以逐位的判断答案,是否可以通过减少某一位的1仍能达到m层,那样我们这个1就可以去掉,也就是不断地更新答案,这样就好了。

      反思:因为最后的答案可能是2^p,但是这样逐位的判断不能讲答案加回2^p,所以需要将答案的初值设为1.

    /**************************************************************
        Problem: 2165
        User: BLADEVIL
        Language: C++
        Result: Accepted
        Time:20640 ms
        Memory:11392 kb
    ****************************************************************/
     
    //By BLADEVIL
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define maxn 110
    #define maxx 60
    #define LL long long
     
    using namespace std;
     
    LL g[maxn][maxn][maxn],p[maxn][maxn],q[maxn][maxn];
    LL n,m;
     
    void solve() {
        LL t,ans=1;
        scanf("%d%lld",&n,&m);
        memset(g,0,sizeof(g));
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++) {
                t=0;
                scanf("%lld",&g[0][i][j]),g[0][i][j]=min(g[0][i][j],m);
                if (i==1) t=max(t,g[0][i][j]);
            }
        if (t==m) {
            printf("1
    ");
            return;
        }
        int k;
        for (k=1;k<=maxx;k++) {
            t=0;
            for (int i=1;i<=n;i++)
                for (int j=1;j<=n;j++) {
                    for (int mid=1;mid<=n;mid++)
                        if (g[k-1][i][mid]&&g[k-1][mid][j])
                            g[k][i][j]=max(g[k][i][j],g[k-1][i][mid]+g[k-1][mid][j]);
                    g[k][i][j]=min(g[k][i][j],m);
                    if (i==1) t=max(t,g[k][i][j]);
                }
            if (t==m) break;
        }
        memcpy(p,g[--k],sizeof(p));
        for (ans+=1LL<<k--;k>=0;k--) {
            memset(q,0,sizeof(q));
            t=0;
            for (int i=1;i<=n;i++)
                for (int j=1;j<=n;j++) {
                    for (int mid=1;mid<=n;mid++)
                        if (p[i][mid]&&g[k][mid][j])
                            q[i][j]=max(q[i][j],p[i][mid]+g[k][mid][j]);
                    q[i][j]=min(q[i][j],m);
                    if (i==1) t=max(t,q[i][j]);
                }
            if (t!=m) {
                ans+=1LL<<k;
                memcpy(p,q,sizeof(p));
            }
        }
        printf("%lld
    ",ans);
    }
     
    int main() {
        int test;
        scanf("%d",&test);
        while (test--) solve();
        return 0;
    }
  • 相关阅读:
    .net core 之Hangfire任务调度
    .net core 在扩展中使用接口实例之IServiceProvider
    .net core webapi 配置swagger调试界面
    c# async/await异步编程死锁的问题
    c# 关于async/await异步编程的浅析和使用
    后端向服务器发送客户端请求--HttpWebRequest
    FluentAPI关系映射配置
    FluentAPI配置
    AutoFac与ASP.NET MVC结合使用
    Log4Net快速配置
  • 原文地址:https://www.cnblogs.com/BLADEVIL/p/3625384.html
Copyright © 2011-2022 走看看