Codeforces 1016C Vasya And The Mushrooms(动态规划)

题目链接:Vasya And The Mushrooms

题意

在一个 2×n 2 × n 的网格内,每一格都有一个蘑菇,第一行第 i i 格内的蘑菇每分钟长大 ai,第二行第 i i 格内的蘑菇每分钟长大 bi Vasya V a s y a 从第 1 1 行第 1 列的网格开始走起,每分钟都只能往相邻网格内移动,每一格蘑菇都必须经过一次(不能多于一次),最后不必回到初始位置,问如何规划路线才能使 Vasya V a s y a 收获的蘑菇最多。

输入

第一行包含一个整数 n (1n3×105) n   ( 1 ≤ n ≤ 3 × 10 5 ) ,第二行为 n n 个整数 a1,a2,,an,第三行为 n n 个整数 b1,b2,,bn ,其中 1ai,bi106 1 ≤ a i , b i ≤ 10 6 。

输出

输出最大能够收获的蘑菇数量。

样例

输入
3
1 2 3
6 5 4
输出
70
提示
最优的路线如下:

最后收获的蘑菇为: 01+12+23+34+45+56=70 0 · 1 + 1 · 2 + 2 · 3 + 3 · 4 + 4 · 5 + 5 · 6 = 70
输入
3
1 1000 10000
10 100 100000
输出
543210
提示
最优的路线如下:

最后收获的蘑菇为: 01+110+2100+31000+410000+5100000=543210 0 · 1 + 1 · 10 + 2 · 100 + 3 · 1000 + 4 · 10000 + 5 · 100000 = 543210
题解

由于每个网格都必须经过一次,所以从左上角开始的路线只有两类:“ ↓→↑→ ” 折返以及在某一次往右时停止折返,一直往右直到最后一格,然后返回,一般的情况如下(也可能在第二行一直往右,到最后从第一行返回):

因此就是枚举中断往返开始一直往右的点,取最大值,在枚举中间点的时候,每次都需要 O(1) O ( 1 ) 地求出贡献,首先用 dfs d f s 预处理出 “ ↓→↑→ ” 走法的每个点的系数(从左上角点按照“下上右”的顺序 dfs d f s 就可以得到):

然后从右往左递推一下后半段(先往右到最后,再往左回来的部分)的贡献,首先假设到某个点 i i 的时候的系数为 x,则后面接着所有点的系数为:

继续算从第 i2 i − 2 个点开始右转的贡献:

其中 x4 x − 4 为第 i2 i − 2 个点上面第二张系数图中对应的系数,对比上一张系数图可以发现,从第 i i 列到第 n 列所有的系数贡献都减 2 2 ,而从第 i2 到第 i1 i − 1 列的贡献需要根据 i i 的位置进行计算,因此就可以从 n 1 1 递推得到从任何一列开始右转的贡献,最终 O(2n) 地枚举转折点取最大值就能得到答案。

过题代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cstring>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <algorithm>
#include <functional>
#include <iomanip>
using namespace std;

#define LL long long
const int maxn = 300000 + 100;
int n;
bool vis[2][maxn];
LL num[2][maxn], c[2][maxn], L[2][maxn], R[2][maxn];
LL sum[maxn];
const int dir[3][2] = {1, 0, -1, 0, 0, 1};

bool in(int x, int y) {
    return x >= 0 && x < 2 && y >= 0 && y < n;
}

void dfs(int x, int y, LL cc) {
    vis[x][y] = true;
    c[x][y] = cc;
    for(int i = 0; i < 3; ++i) {
        int xx = x + dir[i][0];
        int yy = y + dir[i][1];
        if(in(xx, yy) && !vis[xx][yy]) {
            L[xx][yy] = L[x][y] + cc * num[x][y];
            dfs(xx, yy, cc + 1);
        }
    }
}

int main() {
    #ifdef Dmaxiya
        freopen("test.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
    #endif // Dmaxiya
    ios::sync_with_stdio(false);

    while(scanf("%d", &n) != EOF) {
        memset(sum, 0, sizeof(sum));
        for(int i = 0; i < 2; ++i) {
            for(int j = 0; j < n; ++j) {
                scanf("%I64d", &num[i][j]);
                sum[j] += num[i][j];
                vis[i][j] = false;
                R[i][j] = 0;
            }
        }
        for(int i = n - 2; i >= 0; --i) {
            sum[i] += sum[i + 1];
        }
        dfs(0, 0, 0);
        int Begin_up, Begin_down;
        if(n % 2 == 0) {
            Begin_up = n - 2;
            LL cc = c[0][n - 2];
            R[0][n - 2] = cc * num[0][n - 2] + (cc + 1) * num[0][n - 1] + (cc + 2) * num[1][n - 1] + (cc + 3) * num[1][n - 2];
            Begin_down = n - 1;
            cc = c[1][n - 1];
            R[1][n - 1] = cc * num[1][n - 1] + (cc + 1) * num[0][n - 1];
        } else {
            Begin_up = n - 1;
            LL cc = c[0][n - 1];
            R[0][n - 1] = cc * num[0][n - 1] + (cc + 1) * num[1][n - 1];
            Begin_down = n - 2;
            cc = c[1][n - 2];
            R[1][n - 2] = cc * num[1][n - 2] + (cc + 1) * num[1][n - 1] + (cc + 2) * num[0][n - 1] + (cc + 3) * num[0][n - 2];
        }
        for(int i = Begin_up; i - 2 >= 0; i -= 2) {
            LL cc = c[0][i - 2];
            R[0][i - 2] = R[0][i] - sum[i] * 2;
            R[0][i - 2] += cc * num[0][i - 2] + (cc + 1) * num[0][i - 1];
            cc += (n - i) * 2 + 2;
            R[0][i - 2] += cc * num[1][i - 1] + (cc + 1) * num[1][i - 2];
        }
        for(int i = Begin_down; i - 2 >= 0; i -= 2) {
            LL cc = c[1][i - 2];
            R[1][i - 2] = R[1][i] - sum[i] * 2;
            R[1][i - 2] += cc * num[1][i - 2] + (cc + 1) * num[1][i - 1];
            cc += (n - i) * 2 + 2;
            R[1][i - 2] += cc * num[0][i - 1] + (cc + 1) * num[0][i - 2];
        }
        LL aans = 0;
        for(int i = 0; i < 2; ++i) {
            for(int j = 0; j < n; ++j) {
                if((i + j) % 2 == 0) {
                    aans = max(aans, L[i][j] + R[i][j]);
                }
            }
        }
        printf("%I64d\n", aans);
    }

    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值