首页 > 其他分享 >P6772 [NOI2020] 美食家 题解

P6772 [NOI2020] 美食家 题解

时间:2022-10-09 22:00:38浏览次数:68  
标签:fir ch int 题解 美食家 NOI2020 Base 复杂度 LL

一道不错的题目。

一个朴素的 dp 就是 \(f_{i,x}\) 表示时间 \(i\) 时从 1 走到 \(x\) 的最大美味值,就有转移 \(f_{i,v_j}=\max\{f_{i-w_j,u_j}+c_{v_j}+美食节贡献\}\),结合性质 1 判下环有 50 分。

考虑 \(k=0\) 并且 \(w_i=1\) 的情况,就是一个经典问题:\(n\) 点 \(m\) 边,问恰好经过 \(k\) 条边情况下的最长路,有 \(f_{i,v_j}=\max\{f_{i-1,u_j}+c_{v_j}\}\)。

考虑点权转边权,每一条边边权是指向点的点权,用邻接矩阵存一下就有 \(f_{i,v_j}=\max\{f_{i-1,u_j}+d_{u_j,v_j}\}\)。

这实际上是一种矩阵形式,新定义矩阵乘法 \(C=A\times B\) 有 \(C_{i,j}=\max\{A_{i,k}+B_{k,j}\}\),然后可证这个运算满足结合律,因此可以考虑将 \(f_i\) 看成一个行向量(一行的矩阵),就有 \(f_t=f_0\times d^t\),其中 \(f_{0,1}=c_1\) 其余为 -INF,邻接矩阵 \(d\) 中没有边的都是 -INF,最后答案 \(f_{t,x_0},x=1\),如果是负的就说明无解。

然后考虑 \(w_i\ne1\) 的情况,考虑一条边 \((u,v,w)\),拆成若干个点 \(u\to e_1\to e_2\to...\to e_w\to v\),这样就消除了这个情况,但是按边来拆点点数是 \(n+4m\),\(m\) 比 \(n\) 大得多,不大行,因此考虑按点来拆,将一个点拆成 5 个点,\(u_1\to u_2\to u_3\to u_4\to u_5\),边权全部都是 0,一条边 \((u,v,w)\) 就连边 \(u_w\to v_1\),意义在于前 \(w-1\) 条边边权都是 0 没有贡献,只有最后一条边有贡献,这样可以过 \(k=0\) 的点。

考虑 \(k\ne0\) 的情况,由于 \(k\le200\) 因此考虑按照 \(k\) 个美食节(按时间升序排序)划分,对于每两个美食节之间我们使用朴素的 dp 转移,然后每转移到一个美食节 \((t,x,y)\) 那么 \(f_{t,x_0}\leftarrow f_{t,x_0}+y\),这样可以做到复杂度 \(O(k\times(5n)^3\log t)\),能获得 85 分,\(\log t\) 是每次朴素 dp 转移时指数复杂度。

注意到我们可以预处理出 \(d^1,d^2,d^4,d^8,...,d^{2^{29}}\),就是二进制处理,预处理的复杂度是 \(O((5n)^3\log t)\),这样每次朴素 dp 时我们可以直接二进制拆出来而不需要每次重复计算 \(d^{2^p}\),又因为 \(f_t\) 实际上是一个行向量(只有一行),所以 \(f_t\) 乘上这些矩阵的单次实际复杂度是 \(O((5n)^2\log t)\),成功优化了矩阵快速幂的 \((5n)^3\) 复杂度,两个复杂度加起来就是总复杂度可以过。

Code:

/*
========= Plozia =========
	Author:Plozia
	Problem:P6772 [NOI2020] 美食家
	Date:2022/10/9
========= Plozia =========
*/

#include <bits/stdc++.h>
typedef long long LL;
LL Max(LL fir, LL sec) { return (fir > sec) ? fir : sec; }

const int MAXN = 50 + 5, MAXM = 501 + 5, MAXK = 200 + 5;
int n, m, t, k, ys[MAXN][7];
LL c[MAXN];
struct node
{
	int t, x; LL y;
	bool operator <(const node &fir)const { return t < fir.t; }
}a[MAXK];
struct Matrix
{
	int n, m; LL a[MAXN * 5][MAXN * 5];
	Matrix operator *(const Matrix &fir)
	{
		Matrix tmp; tmp.n = n, tmp.m = fir.m; memset(tmp.a, -0x3f, sizeof(tmp.a));
		for (int i = 1; i <= n; ++i)
			for (int k = 1; k <= m; ++k)
				for (int j = 1; j <= fir.m; ++j)
					if (a[i][k] >= 0 && fir.a[k][j] >= 0) tmp.a[i][j] = Max(tmp.a[i][j], a[i][k] + fir.a[k][j]);
		return tmp;
	}
}Base, dis, fact[30];

int Read()
{
	int sum = 0, fh = 1; char ch = getchar();
	for (; ch < '0' || ch > '9'; ch = getchar()) fh -= (ch == '-') << 1;
	for (; ch >= '0' && ch <= '9'; ch = getchar()) sum = (sum << 3) + (sum << 1) + (ch ^ 48);
	return sum * fh;
}

int main()
{
	n = Read(), m = Read(), t = Read(), k = Read(); dis.n = 5 * n, dis.m = 5 * n; memset(dis.a, -0x3f, sizeof(dis.a));
	for (int i = 1; i <= n; ++i) c[i] = Read();
	for (int i = 1; i <= n; ++i) for (int j = 1; j <= 5; ++j) ys[i][j] = 5 * (i - 1) + j;
	for (int i = 1; i <= n; ++i) for (int j = 1; j < 5; ++j) dis.a[ys[i][j]][ys[i][j + 1]] = 0;
	for (int i = 1; i <= m; ++i)
	{
		int x = Read(), y = Read(), z = Read();
		dis.a[ys[x][z]][ys[y][1]] = c[y];
	}
	fact[0] = dis; for (int i = 1; i <= 29; ++i) fact[i] = fact[i - 1] * fact[i - 1];
	for (int i = 1; i <= k; ++i) a[i].t = Read(), a[i].x = Read(), a[i].y = Read();
	std::sort(a + 1, a + k + 1); Base.n = 1, Base.m = 5 * n; memset(Base.a, -0x3f, sizeof(Base.a)); Base.a[1][1] = c[1];
	int Last = 0; a[k + 1] = (node){t, 0, 0};
	for (int i = 1; i <= k + 1; ++i)
	{
		int tmp = a[i].t - Last;
		for (int j = 0; j <= 29; ++j) if ((tmp >> j) & 1) Base = Base * fact[j];
		if (Base.a[1][ys[a[i].x][1]] >= 0) Base.a[1][ys[a[i].x][1]] += a[i].y; Last = a[i].t;
	}
	if (Base.a[1][1] < 0) puts("-1"); else printf("%lld\n", Base.a[1][1]); return 0;
}

标签:fir,ch,int,题解,美食家,NOI2020,Base,复杂度,LL
From: https://www.cnblogs.com/Plozia/p/16773840.html

相关文章

  • 校内集训 小朋友的数字 题解
    校内集训小朋友的数字题解目录校内集训小朋友的数字题解题目分析思路代码题目不想调格式了,直接粘截图了……分析这道题就是简简单单的贪心,再加上个前缀和就行......
  • LG5219 无聊的水题I 题解
    传送门题意求有多少节点数为\(n\)的树,使得节点中最大的度数为\(m\)。节点有标号,两棵树不同当且仅当一对节点在一棵树中有连边,另一棵树中没有连边。\(1\len,m\le......
  • CF896D Nephren Runs a Cinema 题解
    顺手搬一下吧···inluogu和其他题解不太一样的柿子。把0元,50元,100元分别看成\(-1\),\(0\),\(1\),则问题转化成有多少种由\(-1\),\(0\),\(1\),构成的长为\(n\)的序......
  • 「题解」Codeforces 1572B Xor of 3
    我知道你很急,但你先别急。我急了我急了我急了。如果直接上去莽构造的话,很可能就是像我一样大分讨的后果。先特判掉全是1,或者1的个数是奇数的情况。我的做法是考虑所......
  • 洛谷 P2387 [NOI2014] 魔法森林 题解【动态加点 SPFA】
    题目大意给定一个由\(n\)个点\(m\)条边的无向图,每条边有权值\((a,b)\),求一条路径使这条路径上的\((a_{\max}+b_{\max})\)最小。思路正解应该是LCT动态维护MST......
  • LeetCode 字符串相乘算法题解 All In One
    LeetCode字符串相乘算法题解AllInOnejs/ts实现字符串相乘jsbignumbermultiply/js大数相乘字符串相乘原理&图解LeetCode43.MultiplyStringsLee......
  • R 包安装常见问题解决
    1.导读日常中使用R语言进行数据分析,或者画图的读者,相信一定逃不过的一个操作就是安装R包,那么在R包安装过程中,可能会出现一些问题,有时候这些问题并不是R包仓库下载过程中......
  • 【题解】sequence
    题意定义一个满足下列两个条件之一的序列\(a\)为单谷序列:\(\exists1\leqk\leqn\),有\(a_1<...<a_k>a_{k+1}>...>a_n\)\(\exists1\leqk\leq......
  • 2022洛阳师范学院ACM实验室招新竞赛题解
    A萌新签到题目描述欢迎大家来参加2022洛阳师范学院ACM实验室新生赛,我们实验室全体学长学姐从暑假一直期盼着你们的到来。我们的小萌新那么可爱,学长学姐肯定不会为难大......
  • P4967 黑暗打击 题解
    P4967黑暗打击题解目录P4967黑暗打击题解题目声明分析过程前置知识矩阵加速欧拉函数指数循环节转移矩阵推导利用指数循环节降低时间复杂度代码题目洛谷P4967黑暗......