看完题面想了一会发现只会写$n^3$,愣了一会才想出了单调队列优化的做法。

90分算法:

设$f_{i, j, k}$表示第$i$分钟在第$j$座城市已经走了$k$步的最大价值,转移显然,时间复杂度$O(n^3)$。

但是我没有实现它。

100分算法:

思考一下最终的答案是怎样选出来的,我们把矩阵画出来:

发现题目可以转化为在这个矩阵上选若干个斜对角线,使得每一列都有且仅有一个被选到,最后获得的总价值为所有选到的格子上的值再减去所有斜对角线开始的格子对应的代价,使这个总价值最大。

设$f_{i, j}$表示到第$i$分钟,当前再$j$能选到的最大价值,那么发现最多只能从$1-p$层上转移过来。

$f_{i, j} = max(max(f_{i - k,o}) + calc(i- k, i) - cost_{pos(j, k)}) (1 \leq k \leq p - 1) (1 \leq o \leq n)$

$calc(i, j)$表示这一条对角线(从$i$层到$j$层)上的价值总和,可以通过斜线上预处理前缀和得到,$pos(i, j)$表示$i$上移$j$层所到达的纵坐标,$cost_{i}$表示在第$i$个城市买机器人的代价。

那么对每一条斜的对角线维护一个单调队列即可。

时间复杂度$O(n^2)$。

我还是没有实现它。

介绍一种dalao的思路。(第二个id叫Ghastlcon)的大佬,他的Luogu博客中这篇文章看不了了……

有一个小trick就是把下标从$0$到$n - 1$编号,这样子上面定义的$pos(i, j) = ((i - j) \% n + n) \% n$,这样子做前缀和的时候也比较方便。

其实我们发现$f$的第二维是没r用的,所以可以直接拿掉,因为在一个结束的位置并不影响在下一个开始的位置,我们要的只是这个最大值。

把前缀和$g$完整地写出来,有:$f_{i} = max(f_{j} + g_{i} - g_{j - 1} - cost_{j})  (1 \leq i - j \leq p - 1)$。

可以把之后与$i$有关的项拿到外面来,就可以用单调队列优化了。

时间复杂度$O(n^2)$。

Code:

#include <cstdio>
#include <cstring>
using namespace std; const int N = ; int n, m, k, a[N], g[N][N], f[N]; inline void read(int &X) {
X = ; char ch = ; int op = ;
for(; ch > ''|| ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} struct PriQueue {
int lst[N], pos[N], l, r; inline void init() {
l = , r = ;
} inline void push(int x, int val) {
for(; l <= r && lst[r] < val; --r);
lst[++r] = val, pos[r] = x;
} inline void pop(int p) {
for(; l <= r && pos[l] < p; ++l);
} } q[N]; inline int pos(int x, int len) {
return ((x - len) % n + n) % n;
} inline void chkMax(int &x, int y) {
if(y > x) x = y;
} int main() {
read(n), read(m), read(k);
for(int i = ; i < n; i++)
for(int j = ; j <= m; j++)
read(g[i][j]);
for(int i = ; i < n; i++) read(a[i]); for(int j = ; j <= m; j++)
for(int i = ; i < n; i++)
g[i][j] += g[(i + n - ) % n][j - ]; for(int i = ; i < n; i++) q[i].init(); for(int i = ; i < n; i++) {
int now = pos(i, -);
q[now].push(, -a[i]);
} memset(f, , sizeof(f)); f[] = ;
for(int i = ; i <= m; i++) {
for(int j = ; j < n; j++) {
int now = pos(j, i - );
chkMax(f[i], q[now].lst[q[now].l] + g[pos(j, )][i]);
} for(int j = ; j < n; j++) {
int now = pos(j, i - );
q[now].pop(i - k + );
q[now].push(i, f[i] - g[pos(j, )][i] - a[j]);
}
} printf("%d\n", f[m]);
return ;
}

Luogu 1070 道路游戏的更多相关文章

  1. [luogu 1070]道路游戏(NOIP2009T4)

    题目链接 题解: 题目描述好长啊.... 大概就是设一下$f[i]$表示第i秒的最大价值 首先枚举时间,然后因为机器人这一秒无论在哪里都是有可能的,所以要枚举一下每个点,又因为最多走p秒所以再枚举一下 ...

  2. [luogu]P1070 道路游戏[DP]

    [luogu]P1070 道路游戏 题目描述小新正在玩一个简单的电脑游戏.游戏中有一条环形马路,马路上有 n 个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针 ...

  3. luogu P1070 道路游戏

    传送门 这里设\(f_i\)表示时刻\(i\)的答案 转移的话在\([i-p+1,i-1]\)之间枚举j,然后考虑从哪个点走过来 复杂度为\(O(n^3)\) // luogu-judger-enab ...

  4. 洛谷 P1070 道路游戏 解题报告

    P1070 道路游戏 题目描述 小新正在玩一个简单的电脑游戏. 游戏中有一条环形马路,马路上有\(n\)个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针顺序依 ...

  5. 1070 Bash游戏 V4

    1070 Bash游戏 V4 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 有一堆石子共有N个.A B两个人轮流拿,A先拿.每次拿的数量最少1个,最多不超过对手上 ...

  6. 1070 Bash 游戏 V4

    传送门 1070 Bash游戏 V4   基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 有一堆石子共有N个.A B两个人轮流拿,A先拿.每次拿的数量最少1个,最多 ...

  7. 洛谷P1070 道路游戏

    P1070 道路游戏 题目描述 小新正在玩一个简单的电脑游戏. 游戏中有一条环形马路,马路上有 n 个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针顺序依次将 ...

  8. 洛谷 P1070 道路游戏 DP

    P1070 道路游戏 题意: 有一个环,环上有n个工厂,每个工厂可以生产价格为x的零钱收割机器人,每个机器人在购买后可以沿着环最多走p条边,一秒走一条,每条边不同时间上出现的金币是不同的,问如何安排购 ...

  9. 51 Nod 1070 Bash游戏v4(斐波那契博弈)

    这题的证明看不太懂,日后再重做... 1070 Bash游戏 V4  基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题  收藏  关注 有一堆石子共有N个.A B两个 ...

随机推荐

  1. System Error:/usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.15' not found

    System Error:/usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.15' not found 1.运行程序是,系统报错库文件libstdc++. ...

  2. leetcode344

    public class Solution { public string ReverseString(string s) { var list = s.Reverse(); StringBuilde ...

  3. maven错误

    maven-enforcer-plugin (goal "enforce") is ignored by m2e. Plugin execution not covered by ...

  4. WINRAR 自解压脚本命令及变量

    自解压脚本命令 Path=d:\ ;绝对路径 ;Path=.\在当前文件夹中创建 ;Path=在“Program Files”中创建 ;在当前文件夹创建,无语句 Setup=释放后运行 Presetu ...

  5. Nginx Windows 安装启动

    原文连接:http://tengine.taobao.org/book/appendix_c.html#nginxwindows 下载 Nginx是开源软件,用户可以访问 http://nginx.o ...

  6. as3 分发事件无法接收

    最简单的.直接用舞台接收. 如: stage.addEventListener("ok",okH);

  7. ios 确定文字所占矩形框大小

    labelFrame.size = [self.label.text sizeWithFont:self.label.font constrainedToSize:CGSizeMake(self.la ...

  8. Git revert merge

    从history1分出来的A, B两个branch A上有一些更改,例如 changeA2 changeA1 history1 B上有一些更改,例如 changeB2 changeB1 history ...

  9. JVM gc介绍

    Java语言出来之前,大家都在拼命的写C或者C++的程序,而此时存在一个很大的矛盾,C++等语言创建对象要不断的去开辟空间,不用的时候有需要不断的去释放控件,既要写构造函数,又要写析构函数,很多时候都 ...

  10. Nginx 错误汇总

    1. Upstream timed out (110: Connection timed out) while reading response header from upstream 这种情况主要 ...