zoukankan      html  css  js  c++  java
  • BZOJ4386 : [POI2015]Wycieczki

    将每个点拆成三个点,并将转移转化为矩阵乘法,然后倍增即可求出第$k$短路的长度,注意对爆long long情况的处理。

    时间复杂度$O(n^3log k)$。

    #include<cstdio>
    #define N 121
    typedef long long ll;
    int n,m,B,T,i,j,k,x,y,z,f[N][3],v[N];ll K,a[62][N][N],b[N][N],c[N][N],ans;
    void mul(ll a[][N],ll b[][N],ll c[][N]){
      for(int i=0;i<T;i++)for(int j=0;j<T;j++){
        c[i][j]=0;
        for(int k=0;k<T;k++)if(a[i][k]&&b[k][j]){
          if(a[i][k]<0||b[k][j]<0){c[i][j]=-1;break;}
          if(a[i][k]>K/b[k][j]){c[i][j]=-1;break;}
          c[i][j]+=a[i][k]*b[k][j];
          if(c[i][j]>K){c[i][j]=-1;break;}
        }
      }
    }
    bool check(){
      ll t=0;
      for(int i=0;i<T;i++)if(c[0][i]&&v[i]){
        if(c[0][i]<0)return 0;
        if(c[0][i]>K/v[i])return 0;
        t+=c[0][i]*v[i];
        if(t>K)return 0;
      }
      return t<K;
    }
    int main(){
      scanf("%d%d%lld",&n,&m,&K);
      for(T=i=1;i<=n;i++)for(j=0;j<3;j++)f[i][j]=T++;
      a[0][0][0]++;
      for(i=1;i<=n;i++){
        for(j=0;j<2;j++)a[0][f[i][j]][f[i][j+1]]++;
        a[0][0][f[i][0]]++;
      }
      while(m--)scanf("%d%d%d",&x,&y,&z),a[0][f[y][z-1]][f[x][0]]++,v[f[y][z-1]]++;
      for(B=0;(1LL<<B)<=K*3;B++);
      for(i=1;i<B;i++)mul(a[i-1],a[i-1],a[i]);
      for(i=0;i<T;i++)b[i][i]=1;
      for(i=B-1;~i;i--){
        mul(b,a[i],c);
        if(check())for(ans|=1LL<<i,j=0;j<T;j++)for(k=0;k<T;k++)b[j][k]=c[j][k];
      }
      ans++;
      if(ans>K*3)ans=-1;
      return printf("%lld",ans),0;
    }
    

      

  • 相关阅读:
    Java正则表达式, 提取双引号中间的部分
    如何快速找到未知长度单链表的中心点的值
    西格玛
    对数
    jquery显示隐藏toggle
    JavaScript:改变li前缀图片和样式
    jquery点击改变图片src源码并toggle
    jquery点击改变class并toggle
    linux下合并两个文件夹
    编译安装httpd
  • 原文地址:https://www.cnblogs.com/clrs97/p/5271150.html
Copyright © 2011-2022 走看看