zoukankan      html  css  js  c++  java
  • 【洛谷P6190】[NOI Online 入门组] 魔法

    前言

    提高组心态爆炸,来入门组划划水。
    话说这题为什么能评到紫啊

    题目

    题目链接:https://www.luogu.com.cn/problem/P6190
    C 国由 \(n\) 座城市与 \(m\) 条有向道路组成,城市与道路都从 \(1\) 开始编号,经过 \(i\) 号道路需要 \(t_i\) 的费用。
    现在你要从 \(1\) 号城市出发去 \(n\) 号城市,你可以施展最多 \(k\) 次魔法,使得通过下一条道路时,需要的费用变为原来的相反数,即费用从 \(t_i\) 变为 \(-t_i\)。请你算一算,你至少要花费多少费用才能完成这次旅程。
    注意:使用魔法只是改变一次的花费,而不改变一条道路自身的 \(t_i\);最终的费用可以为负,并且一个城市可以经过多次(包括 \(n\) 号城市)。

    思路

    当时下午看别人截图发给我这道题,没截数据范围,心想那不是分层图最短路 sb 题么。
    然后今天看到 \(k\leq 10^6\)。完蛋。
    有一说一,其实也不难。

    \(f[k][i][j]\) 表示从 \(i\)\(j\) 使用不超过 \(k\) 次膜法的最短路,显然有

    \[f[k][i][j]=min(f[\frac{k}{2}][i][l]+f[\frac{k}{2}][l][j]) \]

    先用 Floyd 求出最短路,然后矩阵乘法跑 t-1 次即可。
    挺显然的吧。。。不知道倍增可不可以做。
    时间复杂度 \(O(n^3+n^2m+n^3\log k)\)

    代码

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    
    const int N=110,M=2510;
    int n,m,t;
    ll dis[N][N];
    
    struct edge
    {
    	int u,v,dis;
    }e[M];
    
    struct matrix
    {
    	ll a[N][N];
    	
    	matrix()
    	{
    		memset(a,0x3f3f3f3f,sizeof(a));
    	}
    	
    	friend matrix operator *(matrix a,matrix b)
    	{
    		matrix c;
    		for (int i=1;i<=n;i++)
    			for (int j=1;j<=n;j++)
    				for (int k=1;k<=n;k++)
    					c.a[i][j]=min(c.a[i][j],a.a[i][k]+b.a[k][j]);
    		return c;
    	}
    }mat;
    
    matrix fpow(matrix f,int k)
    {
    	matrix ans;
    	memcpy(ans.a,f.a,sizeof(ans.a));
    	for (;k;k>>=1,f=f*f)
    		if (k&1) ans=ans*f;
    	return ans;
    }
    
    int main()
    {
    	memset(dis,0x3f3f3f3f,sizeof(dis));
    	scanf("%d%d%d",&n,&m,&t);
    	for (int i=1,x,y,z;i<=m;i++)
    	{
    		scanf("%d%d%d",&x,&y,&z);
    		dis[x][y]=z;
    		e[i].u=x; e[i].v=y; e[i].dis=z;
    	}
    	for (int i=1;i<=n;i++)
    		dis[i][i]=0;
    	for (int k=1;k<=n;k++)
    		for (int i=1;i<=n;i++)
    			for (int j=1;j<=n;j++)
    				if (i!=j && j!=k && i!=k)
    					dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
    	if (!t) return !printf("%lld",dis[1][n]);
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=n;j++)
    		{
    			mat.a[i][j]=dis[i][j];
    			for (int k=1;k<=m;k++)
    				mat.a[i][j]=min(mat.a[i][j],dis[i][e[k].u]+dis[e[k].v][j]-e[k].dis);
    		}
    	matrix ans=fpow(mat,t-1);
    	printf("%lld",ans.a[1][n]);
    	return 0;
    }
    
  • 相关阅读:
    HDU
    CodeForces
    CodeForces
    TensorFlow下利用MNIST训练模型并识别自己手写的数字
    李宏毅机器学习笔记2:Gradient Descent(附带详细的原理推导过程)
    李宏毅机器学习笔记1:Regression、Error
    tensorflow相关API的学习
    解决winscp中普通用户无法上传、删除、移动文件
    2019最新最全HUSTOJ本地及云端服务器搭建(基于腾讯云服务器)
    解决Ubuntu无法进行SSH连接的问题(以及如何使用SSH)
  • 原文地址:https://www.cnblogs.com/stoorz/p/12447345.html
Copyright © 2011-2022 走看看