BZOJ4386 : [POI2015]Wycieczki

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

时间复杂度$O(n^3\log 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;
}

  

时间: 2024-10-06 22:54:58

BZOJ4386 : [POI2015]Wycieczki的相关文章

【BZOJ-4386】Wycieczki DP + 矩阵乘法

4386: [POI2015]Wycieczki Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 197  Solved: 49[Submit][Status][Discuss] Description 给定一张n个点m条边的带权有向图,每条边的边权只可能是1,2,3中的一种.将所有可能的路径按路径长度排序,请输出第k小的路径的长度,注意路径不一定是简单路径,即可以重复走同一个点. Input 第一行包含三个整数n,m,k(1<=n<=40,1&

[POI2015]Wycieczki

题目描述 给定一张n个点m条边的带权有向图,每条边的边权只可能是1,2,3中的一种.将所有可能的路径按路径长度排序,请输出第k小的路径的长度,注意路径不一定是简单路径,即可以重复走同一个点. 输入输出格式 输入格式: 第一行包含三个整数n,m,k(1<=n<=40,1<=m<=1000,1<=k<=10^18).接下来m行,每行三个整数u,v,c(1<=u,v<=n,u不等于v,1<=c<=3),表示从u出发有一条到v的单向边,边长为c.可能有重

@bzoj - [email&#160;protected] [POI2015] Wycieczki

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 给定一张 n 个点 m 条边的带权有向图,每条边的边权只可能是1,2,3中的一种. 将所有可能的路径按路径长度排序,请输出第 k 小的路径的长度,注意路径不一定是简单路径,即可以重复走同一个点. input 第一行包含三个整数 n, m, k (1<=n<=40,1<=m<

[Poi2015]

[POI2015]?asuchy 一看以为是sb题 简单来说就是每个人获得热量要尽量多 不能找别人 首先这道题好像我自己找不到NIE的情况 很容易想到一个优化 如果一个数/2>另一个数 那么一定选这个数 然后我想着其他的话就随便分配一个 然后会得出下一个 其实这样做是错的 因为你选完之后不知道下一个会不会是来降低我当前选的那一个的热量使得我当前的原来最优变成不是最优 然后这样子 怎么办呢??? 废话 膜题解 膜拜Claris 我们既然不知道下一个会不会来降低热量 不妨把每个食物的状态都定下来 让

bzoj 4385: [POI2015]Wilcze do?y

4385: [POI2015]Wilcze do?y Description 给定一个长度为n的序列,你有一次机会选中一段连续的长度不超过d的区间,将里面所有数字全部修改为0.请找到最长的一段连续区间,使得该区间内所有数字之和不超过p. Input 第一行包含三个整数n,p,d(1<=d<=n<=2000000,0<=p<=10^16).第二行包含n个正整数,依次表示序列中每个数w[i](1<=w[i]<=10^9). Output 包含一行一个正整数,即修改后能

BZOJ 3747: [POI2015]Kinoman( 线段树 )

线段树... 我们可以枚举左端点 , 然后用线段树找出所有右端点中的最大值 . ----------------------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #define rep( i , n ) for( i

【BZOJ 3747】 3747: [POI2015]Kinoman (线段树)

3747: [POI2015]Kinoman Time Limit: 60 Sec  Memory Limit: 128 MBSubmit: 830  Solved: 338 Description 共有m部电影,编号为1~m,第i部电影的好看值为w[i]. 在n天之中(从1~n编号)每天会放映一部电影,第i天放映的是第f[i]部. 你可以选择l,r(1<=l<=r<=n),并观看第l,l+1,-,r天内所有的电影.如果同一部电影你观看多于一次,你会感到无聊,于是无法获得这部电影的好看值

【BZOJ4378】[POI2015]Logistyka 树状数组

[BZOJ4378][POI2015]Logistyka Description 维护一个长度为n的序列,一开始都是0,支持以下两种操作:1.U k a 将序列中第k个数修改为a.2.Z c s 在这个序列上,每次选出c个正数,并将它们都减去1,询问能否进行s次操作.每次询问独立,即每次询问不会对序列进行修改. Input 第一行包含两个正整数n,m(1<=n,m<=1000000),分别表示序列长度和操作次数.接下来m行为m个操作,其中1<=k,c<=n,0<=a<=

BZOJ 4384: [POI2015]Trzy wie?e

4384: [POI2015]Trzy wie?e Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 217  Solved: 61[Submit][Status][Discuss] Description 给定一个长度为n的仅包含'B'.'C'.'S'三种字符的字符串,请找到最长的一段连续子串,使得这一段要么只有一种字符,要么有多种字符,但是没有任意两种字符出现次数相同. Input 第一行包含一个正整数n(1<=n<=1000000),表示字符