zoukankan      html  css  js  c++  java
  • (中等) CF 576D Flights for Regular Customers (#319 Div1 D题),矩阵快速幂。

      In the country there are exactly n cities numbered with positive integers from 1 to n. In each city there is an airport is located.

    Also, there is the only one airline, which makes m flights. Unfortunately, to use them, you need to be a regular customer of this company, namely, you have the opportunity to enjoy flight i from city ai to city bi only if you have already made at least di flights before that.

    Please note that flight i flies exactly from city ai to city bi. It can not be used to fly from city bi to city ai. An interesting fact is that there may possibly be recreational flights with a beautiful view of the sky, which begin and end in the same city.

    You need to get from city 1 to city n. Unfortunately, you've never traveled by plane before. What minimum number of flights you have to perform in order to get to city n?

    Note that the same flight can be used multiple times.

      题意大致就是给一个图,然后每条边有一个限制条件d表示至少已经走过d长度才能打开这条路,然后问最少需要多少步才能从1到n。

      本来看到n的数据范围只有150时就应该想到矩阵的,然而忘记了。。。

      邻接矩阵有一个性质就是他的k次幂的第 i 行 j 列就表示从 i 正好走 k 步到 j 的方案数。然后对于这题,对每条路排序,然后一次次对矩阵进行乘法,当次数到限制条件的时候就增加新的可以走的边,然后继续乘。。。

      但是这样的复杂度就有点。。。了,矩阵快速幂的复杂度是n^3 log k的,然后是m次,所以复杂度(n^3mlogk)的,比较大。。。但是对于CF那样速度巨快的机子,写的好的话也是可以过的。。。

      不过这里可以用位运算加速,因为主要考虑的是矩阵的01,而不是方案数,所以用bitset可以加速很多。。。

    代码如下:

    // ━━━━━━神兽出没━━━━━━
    //      ┏┓       ┏┓
    //     ┏┛┻━━━━━━━┛┻┓
    //     ┃           ┃
    //     ┃     ━     ┃
    //     ████━████   ┃
    //     ┃           ┃
    //     ┃    ┻      ┃
    //     ┃           ┃
    //     ┗━┓       ┏━┛
    //       ┃       ┃
    //       ┃       ┃
    //       ┃       ┗━━━┓
    //       ┃           ┣┓
    //       ┃           ┏┛
    //       ┗┓┓┏━━━━━┳┓┏┛
    //        ┃┫┫     ┃┫┫
    //        ┗┻┛     ┗┻┛
    //
    // ━━━━━━感觉萌萌哒━━━━━━
    
    // Author        : WhyWhy
    // Created Time  : 2015年09月30日 星期三 22时03分41秒
    // File Name     : 1_D.cpp
    
    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <set>
    #include <map>
    #include <string>
    #include <math.h>
    #include <stdlib.h>
    #include <time.h>
    
    #include <bitset>
    
    using namespace std;
    
    const int MaxN=160;
    
    int N;
    
    struct Mat
    {
        bitset <MaxN> num[MaxN];
    
        Mat operator * (const Mat & b) const
        {
            Mat ret;
            for(int i=1;i<=N;++i)
                for(int j=1;j<=N;++j)
                    if(num[i][j])
                        ret.num[i]|=b.num[j];
            return ret;
        }
    };
    
    int M;
    
    struct Edge
    {
        int u,v,d;
    
        bool operator < (const Edge & b) const
        {
            return d<b.d;
        }
    };
    
    Edge E[MaxN];
    Mat ans,map1;
    
    Mat _pow(Mat base,int n)
    {
        Mat ret;
        for(int i=1;i<=N;++i) ret.num[i][i]=1;
    
        while(n)
        {
            if(n&1) ret=ret*base;
            base=base*base;
            n>>=1;
        }
        return ret;
    }
    
    int getans(int R)
    {
        int L=1,M;
        Mat temp=ans*_pow(map1,R);
    
        if(temp.num[1][N]==0)
        {
            ans=temp;
            return 0;
        }
    
        while(R>L)
        {
            M=(L+R)>>1;
            temp=ans*_pow(map1,M);
            if(temp.num[1][N]) R=M;
            else L=M+1;
        }
        return L;
    }
    
    int main()
    {
        //freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
    
        scanf("%d %d",&N,&M);
        for(int i=1;i<=M;++i)
            scanf("%d %d %d",&E[i].u,&E[i].v,&E[i].d);
        sort(E+1,E+M+1);
        ++M;
        E[M].d=1000000000+1000;
        E[M].u=E[M].v=0;
    
        if(E[1].d)
        {
            puts("Impossible");
            return 0;
        }
        
        int t;
    
        map1.num[N][N]=1;
        for(int i=1;i<=N;++i) ans.num[i][i]=1;
        
        map1.num[E[1].u][E[1].v]=1;
        for(int i=2;i<=M;++i)
            if(E[i].d!=E[i-1].d)
            {
                if(t=getans(E[i].d-E[i-1].d))
                {
                    printf("%d
    ",E[i-1].d+t);
                    return 0;
                }
                map1.num[E[i].u][E[i].v]=1;
            }
            else
                map1.num[E[i].u][E[i].v]=1;
    
        puts("Impossible");
        
        return 0;
    }
    View Code
  • 相关阅读:
    十一、异常处理&运行流程
    logback的使用和logback.xml详解
    十、拦截器
    word源代码解析(方便通过源码将word文件转换成html) 持续更新中
    laravel 打印sql
    利用workman进行回复指定用户指定内容
    js 根据val值获取对象key键值
    php添加邀请码
    微信支付退款流程 php
    解决ubuntu下修改环境变量profile后报错,很多常用命令都用不了
  • 原文地址:https://www.cnblogs.com/whywhy/p/4855221.html
Copyright © 2011-2022 走看看