Luogu 1070 道路游戏

看完题面想了一会发现只会写$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_{j - 1} - g_{i} - cost_{j})  (1 \leq i - j \leq p - 1)$。

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

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

Code:

#include <cstdio>
#include <cstring>
using namespace std;

const int N = 1005;

int n, m, k, a[N], g[N][N], f[N];

inline void read(int &X) {
    X = 0; char ch = 0; int op = 1;
    for(; ch > ‘9‘|| ch < ‘0‘; ch = getchar())
        if(ch == ‘-‘) op = -1;
    for(; ch >= ‘0‘ && ch <= ‘9‘; ch = getchar())
        X = (X << 3) + (X << 1) + ch - 48;
    X *= op;
}

struct PriQueue {
    int lst[N], pos[N], l, r;

    inline void init() {
        l = 1, r = 0;
    }

    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 = 0; i < n; i++)
        for(int j = 1; j <= m; j++)
            read(g[i][j]);
    for(int i = 0; i < n; i++) read(a[i]);

    for(int j = 2; j <= m; j++)
        for(int i = 0; i < n; i++)
            g[i][j] += g[(i + n - 1) % n][j - 1];

    for(int i = 0; i < n; i++) q[i].init();

    for(int i = 0; i < n; i++) {
        int now = pos(i, -1);
        q[now].push(0, -a[i]);
    }

    memset(f, 128, sizeof(f)); f[0] = 0;
    for(int i = 1; i <= m; i++) {
        for(int j = 0; j < n; j++) {
            int now = pos(j, i - 1);
            chkMax(f[i], q[now].lst[q[now].l] + g[pos(j, 1)][i]);
        }    

        for(int j = 0; j < n; j++) {
            int now = pos(j, i - 1);
            q[now].pop(i - k + 1);
            q[now].push(i, f[i] - g[pos(j, 1)][i] - a[j]);
        }
    }    

    printf("%d\n", f[m]);
    return 0;
}

原文地址:https://www.cnblogs.com/CzxingcHen/p/9569647.html

时间: 2024-10-11 04:52:36

Luogu 1070 道路游戏的相关文章

Luogu P1070 道路游戏

题面 小新正在玩一个简单的电脑游戏. 游戏中有一条环形马路,马路上有 n 个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针顺序依次将这 n 个机器人工厂编号为1~n,因为马路是环形的,所以第 n 个机器人工厂和第 1 个机器人工厂是由一段马路连接在一起的.小新将连接机器人工厂的这 n 段马路也编号为 1~n,并规定第 i 段马路连接第 i 个机器人工厂和第 i+1 个机器人工厂(1≤i≤n-1),第 n 段马路连接第 n 个机器人工厂和第 1个机器人工厂

[Noip 2009 普及组 T4] [Luogu P1070] 道路游戏

一道很迷的\(dp\). 感谢大爱无疆的sy 开始的时候采用的二维状态但是并不对) 然后把状态改成一维\(AC\) \(Solution\): 状态:开始想的是\(f[i][j]\),表示到达\(i\)时间时在\(j\)点处的最多金币数. 转移方程设置为:\(f[i][j]=max\{f[i-1][j-k]+sum-val[j-k]\}\)其中\(sum\)表示从\(j-k\)走到\(j\)所赚的金币数 但这样是不对的,因为题目中: 也就是上一个机器人消失的地方并不一定要买下一个机器人,而是可以

洛谷P1070 道路游戏

P1070 道路游戏 题目描述 小新正在玩一个简单的电脑游戏. 游戏中有一条环形马路,马路上有 n 个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针顺序依次将这 n 个机器人工厂编号为1~n,因为马路是环形的,所以第 n 个机器人工厂和第 1 个机器人工厂是由一段马路连接在一起的.小新将连接机器人工厂的这 n 段马路也编号为 1~n,并规定第 i 段马路连接第 i 个机器人工厂和第 i+1 个机器人工厂(1≤i≤n-1),第 n 段马路连接第 n 个机器

1153 道路游戏

1153 道路游戏 2009年NOIP全国联赛普及组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 题目描述 Description 小新正在玩一个简单的电脑游戏.游戏中有一条环形马路,马路上有n 个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针顺序依次将这n 个机器人工厂编号为1~n,因为马路是环形的,所以第n 个机器人工厂和第1 个机器人工厂是由一段马路连接在一起的.小新将连接机器人工厂的这n 段马路也编号为

1070 Bash 游戏 V4

传送门 1070 Bash游戏 V4 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 有一堆石子共有N个.A B两个人轮流拿,A先拿.每次拿的数量最少1个,最多不超过对手上一次拿的数量的2倍(A第1次拿时要求不能全拿走).拿到最后1颗石子的人获胜.假设A B都非常聪明,拿石子的过程中不会出现失误.给出N,问最后谁能赢得比赛. 例如N = 3.A只能拿1颗或2颗,所以B可以拿到最后1颗石子. Input 第1行:一个数T,表示后面用作输入测试的数的数量.(1 <

1070 Bash游戏 V4

1070 Bash游戏 V4 有一堆石子共有N个.A B两个人轮流拿,A先拿.每次拿的数量最少1个,最多不超过对手上一次拿的数量的2倍(A第1次拿时要求不能全拿走).拿到最后1颗石子的人获胜.假设A B都非常聪明,拿石子的过程中不会出现失误.给出N,问最后谁能赢得比赛. 例如N = 3.A只能拿1颗或2颗,所以B可以拿到最后1颗石子. Input 第1行:一个数T,表示后面用作输入测试的数的数量.(1 <= T <= 1000) 第2 - T + 1行:每行1个数N.(1 <= N &l

Luogu P1965 转圈游戏

Luogu P1965 转圈游戏 考场上遇到这种题,一定要画图推一下. 不难得到\(ans=(x+m\times 10^k)mod n\). 还有就是用同余定理时一定要仔细思考一下,然后该打快速幂就打. #include<bits/stdc++.h> using namespace std; int n,m,k,x; long long ans; long long quickPower(int b,int p,int k) { long long ans=1; if(!p) { ans=1%

P1070 道路游戏

题目描述 小新正在玩一个简单的电脑游戏. 游戏中有一条环形马路,马路上有 n 个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针顺序依次将这 n 个机器人工厂编号为1~n,因为马路是环形的,所以第 n 个机器人工厂和第 1 个机器人工厂是由一段马路连接在一起的.小新将连接机器人工厂的这 n 段马路也编号为 1~n,并规定第 i 段马路连接第 i 个机器人工厂和第 i+1 个机器人工厂(1≤i≤n-1),第 n 段马路连接第 n 个机器人工厂和第 1个机器人

NOIP2009pj道路游戏[环形DP 转移优化 二维信息]

题目描述 小新正在玩一个简单的电脑游戏. 游戏中有一条环形马路,马路上有 n 个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针顺序依次将这 n 个机器人工厂编号为1~n,因为马路是环形的,所以第 n 个机器人工厂和第 1 个机器人工厂是由一段马路连接在一起的.小新将连接机器人工厂的这 n 段马路也编号为 1~n,并规定第 i 段马路连接第 i 个机器人工厂和第 i+1 个机器人工厂(1≤i≤n-1),第 n 段马路连接第 n 个机器人工厂和第 1个机器人