题意分析

给出一个带权有向图,要求从节点 $1$ 出发,经过恰好 $T$ 的边权和,回到节点 $1$ ,求可经过的最大点权和。特别地,经过的边权和达到部分特殊数时,会有某个点的点权发生改变。

思路分析

朴素算法
  • 时间复杂度: $O(mT)$
  • 理论得分: $40pts$

设 $f_{i,j}$ 表示在节点 $j$ ,经过的边权和为 $i$ 时可经过的最大点权和。很容易可以得出 DP 方程:

$$f_{i,j}=\max_{(x,j)\in E}(f_{i-val(x,j),x})+c_j$$

暴力转移,点权改变的情况特判修改即可。

优化1
  • 时间复杂度: $O(125n^3k\log T)$
  • 理论得分:$75pts$

可以发现 $w$ 的数据范围很小,想到用矩阵快速幂优化。

首先拆点,令所有边边权都为 $1$ ,然后将所求的点权转化为边权:设有 $(u,v,w)\in E$ ,则可以将 $u$ 拆成 $u_0,u_1,...,u_{w-1}$ ,从 $u_{i-1}$ 向 $u_i$ 间连一条边,边权为 $0$ ,然后从 $u_{w-1}$ 向 $v$ 连一条边,边权为 $c_v$ 。

这样,问题就转化为,从节点 $1$ 出发,经过 $T$ 条边,回到节点 $1$ ,求可经过的最大边权和,即最长路。

定义一个广义矩阵乘法 $ans_{i,j}=max(a_{i,k}+b_{k,j})$ 。可以证明这个广义矩阵乘法同样满足矩阵乘法的基本运算律,如结合律。

设邻接矩阵为 $a$ ,可以很容易得出 DP 方程:

$$dp_i=dp_j*a^{i-j}$$

点权改变的情况怎么处理?只要先将时间从小到大排序,然后在相邻的时间之间转移,转移后在改变点权在邻接矩阵中的对应位置修改即可。

优化2
  • 时间复杂度: $O(125n^3\log T+25n^2k\log T)$
  • 理论得分: $100pts$

分析过后可以发现,因为要求的只是 $dp_{T_{1,1}}$ ,因此只要保留 $dp$ 矩阵的第一行即可;另外,发现在转移的时候要多次乘上邻接矩阵 $a$ 的相同次幂,因此可以先预处理出 $a$ 的 $2$ 的整数次幂。这样处理之后可以降低一维的复杂度。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=300;
const ll INF=0xcfcfcfcfcfcfcfcf;
struct Node
{
ll p[N][N];
}a[31];
struct Fes
{
int t,x,y;
#define t(i) b[i].t
#define x(i) b[i].x
#define y(i) b[i].y
}b[N];
int n,m,T,K;
int c[N],id[N][5];
ll dp[N];
Node Max(Node x)
{
Node now;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
now.p[i][j]=INF;
for(int k=1;k<=n;k++)
now.p[i][j]=max(now.p[i][j],x.p[i][k]+x.p[k][j]);
}
return now;
}//广义矩阵乘法
void Maxx(Node x)
{
ll now[N];
for(int i=1;i<=n;i++)
{
now[i]=INF;
for(int j=1;j<=n;j++)
now[i]=max(now[i],dp[j]+x.p[j][i]);
}
for(int i=1;i<=n;i++)
dp[i]=now[i];
}//一维乘二维
void pre()
{
for(int i=1;i<=30;i++)
a[i]=Max(a[i-1]);
}//预处理次幂
void fastpow(int x)
{
for(int i=30;i>=0;i--)
if(x&(1<<i))
Maxx(a[i]);
}//快速幂
bool cmp(Fes x,Fes y)
{
return x.t<y.t;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&T,&K);
for(int i=1;i<=n;i++)
scanf("%d",&c[i]),id[i][0]=i;
memset(a,0xcfcf,sizeof(a));
for(int i=1,u,v,w;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
for(int j=1;j<w;j++)
{
if(!id[u][j])
id[u][j]=++n;
a[0].p[id[u][j-1]][id[u][j]]=0;
}
a[0].p[id[u][w-1]][v]=c[v];//拆点
}
pre();
for(int i=1;i<=K;i++)
scanf("%d%d%d",&t(i),&x(i),&y(i));
sort(b+1,b+K+1,cmp);t(K+1)=T;
memset(dp,0xcfcf,sizeof(dp));dp[1]=c[1];//初状态
for(int i=1,d;i<=K+1;i++)
{
d=t(i)-t(i-1);
fastpow(d);
dp[x(i)]+=y(i);//点权改变
}//在相邻的时间之间转移
printf(dp[1]<0?"-1":"%lld",dp[1]);
return 0;
}

[NOI2020]美食家 题解的更多相关文章

  1. P6772 [NOI2020]美食家

    题目大意 给你一个 \(n\) 个点,\(m\) 条边的有向图,每条边有一个权值 \(w_i\) ,每个节点有一个权值 \(a_i\) . 你从节点 \(1\) 出发,每经过一个节点就可以获得该点的权 ...

  2. [XIN算法应用]NOI2020美食家

    XIN(\(updated 2021.6.4\)) 对于很多很多的题目,发现自己并不会之后,往往会直接冲上一个XIN队算法,然而,这样 \(\huge{\text{鲁莽}}\) 的行为只能获得 TLE ...

  3. [NOI2020] 美食家

    很好,自己会做NOI签到题了,去年只要会这题,再多打点暴力,\(Ag\)到手,希望今年\(NOI\)同步赛过\(Ag\)线吧,得有点拿得出手的成绩证明啊. 考虑\(T\)非常大,\(n\)又很小. 想 ...

  4. 洛谷 P6772 - [NOI2020]美食家(广义矩阵快速幂)

    题面传送门 题意: 有一张 \(n\) 个点 \(m\) 条边的有向图,第 \(0\) 天的时候你在 \(1\) 号城市,第 \(T\) 天的时候你要回到 \(1\) 号城市. 每条边上的边权表示从城 ...

  5. 【NOI2020】美食家(矩阵)

    Description 给定一张有向图,\(n\) 个顶点,\(m\) 条边.第 \(i\) 条边从 \(u_i\) 到 \(v_i\),走完该边的用时为 \(w_i\).每一个点有一个价值 \(c\ ...

  6. XIN队算法

    XIN队算法 注:名称由莫队算法改编而来 从luogu搬过来了... \(newly\;upd:2021.7.8\) \(newly\;upd:2021.6.6\) OI至高算法,只要XIN队算法打满 ...

  7. [BZOJ1691][Usaco2007 Dec]挑剔的美食家

    [BZOJ1691][Usaco2007 Dec]挑剔的美食家 试题描述 与很多奶牛一样,Farmer John那群养尊处优的奶牛们对食物越来越挑剔,随便拿堆草就能打发她们午饭的日子自然是一去不返了. ...

  8. bzoj usaco 金组水题题解(1)

    UPD:我真不是想骗访问量TAT..一开始没注意总长度写着写着网页崩了王仓(其实中午的时候就时常开始卡了= =)....损失了2h(幸好长一点的都单独开了一篇)....吓得赶紧分成两坨....TAT. ...

  9. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

随机推荐

  1. pandas_分类与聚合

    # 分组与聚合 import pandas as pd import numpy as np # 设置列对齐 pd.set_option("display.unicode.ambiguous ...

  2. Python File flush() 方法

    概述 flush() 方法是用来刷新缓冲区的,即将缓冲区中的数据立刻写入文件,同时清空缓冲区,不需要是被动的等待输出缓冲区写入.高佣联盟 www.cgewang.com 一般情况下,文件关闭后会自动刷 ...

  3. Hadoop学习问题记录之基础篇

    目的 记录学习hadoop过程中遇到的基础问题,无关大小.无关困扰时间长短. 问题一 全分布式环境中运行mapred程序,报异常:java.net.NoRouteToHostException: 没有 ...

  4. python 变量的命名规则和注意事项

    命名规则 变量名只能包含字母.数字和下划线.变量名可以字母或下划线打头,但不能以数字打头,例如,可将变量命名为message_1,但不能将其命名为1_message 变量名不能包含空格,但可使用下划线 ...

  5. Chrome划词翻译-Saladict

    Saladict 沙拉查词是一款专业划词翻译扩展,为交叉阅读而生.大量权威词典涵盖中英日韩法德西语,支持复杂的 划词操作.网页翻译.生词本.PDF,以及 Vimium 全键盘操作 . 迄今为止最好用的 ...

  6. 比原Bapp红包应用

    喜迎国庆期间,比原链在自己的移动端钱包Bycoin(下载地址)和google插件钱byone中推出了红包应用,在国庆期间深受大家好评. 那我们今天就来大概介绍一下比原红包,以及基于比原链开发dapp应 ...

  7. ~/.ssh/目录找不到解决方法

    执行 cd ~/.ssh发现.ssh目录找不到 原因是因为没有用root用户ssh登录过,执行一下ssh操作就会自动生成了

  8. 【Java】AES加机解密工具类代码

    import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import javax.crypt ...

  9. C#LeetCode刷题-极小化极大

    极小化极大篇 # 题名 刷题 通过率 难度 375 猜数字大小 II   23.4% 中等 464 我能赢吗   25.5% 中等 486 预测赢家   40.4% 中等 843 猜猜这个单词   2 ...

  10. 使用 VMware Workstation Pro让 PC 提供云桌面服务——学习笔记(三)

    目标 当在前面两篇博客后,我们已经创建了一个能当服务器的虚拟机,这时我们需要通过复制虚拟机来让创建更多虚拟机 操作步骤 1.创建克隆 这里主要是VMware软件的操作 虚拟机->管理->克 ...