zoukankan      html  css  js  c++  java
  • 【洛谷P6772】美食家

    题目

    题目链接:https://www.luogu.com.cn/problem/P6772
    坐落在 Bzeroth 大陆上的精灵王国击退地灾军团的入侵后,经过十余年的休养生息,重新成为了一片欣欣向荣的乐土,吸引着八方游客。小 W 是一位游历过世界各地的著名美食家,现在也慕名来到了精灵王国。

    精灵王国共有 \(n\) 座城市,城市从 \(1\)\(n\) 编号,其中城市 \(i\) 的美食能为小 W 提供 \(c_i\) 的愉悦值。精灵王国的城市通过 \(m\)单向道路连接,道路从 \(1\)\(m\) 编号,其中道路 \(i\) 的起点为城市 \(u_i\) ,终点为城市 \(vi_\),沿它通行需要花费 \(w_i\) 天。也就是说,若小 W 在第 \(d\) 天从城市 \(u_i\) 沿道路 \(i\) 通行,那么他会在第 \(d + w_i\) 天到达城市 \(v_i\)

    小 W 计划在精灵王国进行一场为期 \(T\) 天的旅行,更具体地:他会在第 \(0\) 天从城市 \(1\) 出发,经过 \(T\) 天的旅行,最终在恰好第 \(T\)回到城市 \(1\) 结束旅行。由于小 W 是一位美食家,每当他到达一座城市时(包括第 \(0\) 天和第 \(T\) 天的城市 \(1\)),他都会品尝该城市的美食并获得其所提供的愉悦值,若小 W 多次到达同一座城市,他将获得多次愉悦值。注意旅行途中小 W 不能在任何城市停留,即当他到达一座城市且还未结束旅行时,他当天必须立即从该城市出发前往其他城市。

    对于上图,小 W 一种为期 \(11\) 天的可行旅游方案为 \(1 \to 2 \to 1 \to 2 \to 3 \to 1\)

    • \(0\) 天,小 W 从城市 \(1\) 开始旅行,获得愉悦值 \(1\) 并向城市 \(2\) 出发。
    • \(1\) 天,小 W 到达城市 \(2\),获得愉悦值 \(3\) 并向城市 \(1\) 出发。
    • \(4\) 天,小 W 到达城市 \(1\),获得愉悦值 \(1\) 并向城市 \(2\) 出发。
    • \(5\) 天,小 W 到达城市 \(2\),获得愉悦值 \(3\) 并向城市 \(3\) 出发。
    • \(7\) 天,小 W 到达城市 \(3\),获得愉悦值 \(4\) 并向城市 \(1\) 出发。
    • \(11\) 天,小 W 到达城市 \(1\),获得愉悦值 \(1\) 并结束旅行。
    • 小 W 在该旅行中获得的愉悦值之和为 \(13\)

    此外,精灵王国会在不同的时间举办 \(k\) 次美食节。具体来说,第 \(i\) 次美食节将于第 \(t_i\) 天在城市 \(x_i\) 举办,若小 W 第 \(t_i\) 天时恰好在城市 \(x_i\),那么他在品尝城市 \(x_i\) 的美食时会额外得到 \(y_i\) 的愉悦值。现在小 W 想请作为精灵王国接待使者的你帮他算出,他在旅行中能获得的愉悦值之和的最大值

    思路

    首先如果没有美食节和路径长度,那么这道题就是裸的矩阵乘法。
    我们发现这道题的边权不超过 \(5\),所以考虑将每条边拆成 \(5\) 条边来跑,这样还是相当于边权为 \(1\),但是点的数量为 \(5n\leq 250\)
    此时如果没有美食节,那么仍然直接矩阵乘法即可。
    加入了美食节后,显然要在每两个美食节中间用矩阵快速幂计算出这几天的答案,然后加上美食节贡献。
    但是直接这样做是 \(O(kn^3\log t)\) 的,不可接受。
    发现每次都要计算两次美食节之间的代价大量运算重复,所以可以先预处理出矩阵的 \(2^i\) 幂,然后每次 \(O(\log t)\) 倍增求出。
    然后答案是一个 \(1\times n\) 的矩阵,向量乘矩阵的复杂度是 \(O(n^2)\) 的,这样时间复杂度就被我们降到了 \(O(kn^2\log t)\)
    总时间复杂度 \(O(n^3\log t+kn^2\log t)\)。此处 \(n\) 等于原题中 \(5n\)

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int N=260,LG=30;
    int n,m,t,k,tot,maxn,a[N];
    
    int ID(int x,int y)
    {
    	return y*n+x;
    }
    
    struct node
    {
    	int t,x,a;
    }b[N];
    
    bool cmp(node x,node y)
    {
    	return x.t<y.t;
    }
    
    struct Matrix
    {
    	ll a[N][N];
    	Matrix() { memset(a,0xcf,sizeof(a)); }
    	
    	friend Matrix operator *(const Matrix &a,const Matrix &b)
    	{
    		Matrix c;
    		for (int i=1;i<=maxn;i++)
    			for (int j=1;j<=tot;j++)
    				for (int k=1;k<=tot;k++)
    					c.a[i][j]=max(c.a[i][j],a.a[i][k]+b.a[k][j]);
    		return c;
    	}
    }ans,f[LG+1];
    
    Matrix fpow(Matrix a,int k)
    {
    	for (int i=LG;i>=0;i--)
    		if (k&(1<<i)) a=a*f[i];
    	return a;
    }
    
    int main()
    {
    	scanf("%d%d%d%d",&n,&m,&t,&k);
    	for (int i=1;i<=n;i++)
    	{
    		scanf("%d",&a[i]);
    		for (int j=0;j<4;j++)
    			f[0].a[ID(i,j)][ID(i,j+1)]=0;
    	}
    	tot=5*n;
    	for (int i=1,x,y,z;i<=m;i++)
    	{
    		scanf("%d%d%d",&x,&y,&z);
    		f[0].a[ID(x,z-1)][y]=a[y];
    	}
    	maxn=tot;
    	for (int i=1;i<=LG;i++)
    		f[i]=f[i-1]*f[i-1];
    	maxn=1;
    	for (int i=1;i<=k;i++)
    		scanf("%d%d%d",&b[i].t,&b[i].x,&b[i].a);
    	sort(b+1,b+1+k,cmp);
    	b[k+1].t=t;
    	ans.a[1][1]=a[1];
    	ans=fpow(ans,b[1].t);
    	for (int i=1;i<=k;i++)
    	{
    		ans.a[1][b[i].x]+=b[i].a;
    		ans=fpow(ans,b[i+1].t-b[i].t);
    	}
    	ll WYCtxdy=ans.a[1][1];
    	if (WYCtxdy<0) printf("-1");
    		else printf("%lld",WYCtxdy);
    	return 0;
    }
    
  • 相关阅读:
    常见邮件服务器(接收服务器和发送邮件服务器)地址
    Linux下搭建SVN服务器(CentOS)
    macBook下更新python
    画画练习20180627
    如何用Photoshop画一个发光金币(unity游戏素材教程)
    Python+VSCode+Git 学习总结
    如何在MFC DLL中向C#类发送消息
    MFC信号量使用指南
    回归cnBlogs
    Web自动化测试框架Watir(基于Ruby)
  • 原文地址:https://www.cnblogs.com/stoorz/p/13526485.html
Copyright © 2011-2022 走看看