zoukankan      html  css  js  c++  java
  • [arc067f]yakiniku restaurants

    题意:

    n家饭店,m张餐票,第i家和第i+1家饭店之间的距离是$A_i$,在第i家饭店用掉第j张餐票会获得$B_{i,j}$的好感度,但是从饭店i走到饭店j会有$dis_{i,j}$的代价,可以从任意一个饭店出发,求好感度减代价的差的最大值。

    $2leq Nleq 5000$

    $1leq Mleq 200$

    $1leq A_i,B_{i,j}leq 10^9$

    题解:

    看错了两次题是怎样一种体验。。。开始题意锅了说只能从1出发,然后更正我没看到。。。于是写了个自以为对的傻逼线段树自爆成13分。。。

    其实这题做法很多,可以利用决策单调性二分dp或者建笛卡尔树区间加,我讲一个我写的矩形差分的做法。。。

    直接计算路线的价值比较难,可以反过来考虑每个$B_{i,j}$对哪些答案有影响。

    令$x$为满足$x<i$且$B_{x,j}>B_{i,j}$的最大的$x$,$y$为满足$y>i$且$B_{y,j}>B_{i,j}$的最小的$y$,那么$B_{i,j}$就会对左端点$l∈(x,i]$,右端点$r∈[i,y)$的区间产生贡献。

    容易发现$x$,$y$是单调递增的,所以可以用一条单调栈来维护;把$(x,y)$当成平面上的一个点,那贡献就等价于在整个矩阵上加上一个值,可以用差分前缀和来搞。

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

    代码:

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdio>
     5 #include<cmath>
     6 #include<queue>
     7 #define inf 2147483647
     8 #define eps 1e-9
     9 using namespace std;
    10 typedef long long ll;
    11 ll n,m,L,R,st[5010],num[5010],b[210][5010],l[210][5010],r[210][5010];
    12 ll ans=0,a[5010],pre[5010],sq[5010][5010];
    13 int main(){
    14     scanf("%d%d",&n,&m);
    15     for(int i=1;i<n;i++){
    16         scanf("%lld",&a[i]);
    17         pre[i+1]=pre[i]+a[i];
    18     }
    19     for(int i=1;i<=n;i++){
    20         for(int j=1;j<=m;j++){
    21             scanf("%d",&b[j][i]);
    22         }
    23     }
    24     for(int i=1;i<=m;i++){
    25         L=R=0;
    26         for(int j=1;j<=n;j++){
    27             while(L&&b[i][j]>st[L])L--;
    28             l[i][j]=L?num[L]+1:1;
    29             st[++L]=b[i][j];
    30             num[L]=j;
    31         }
    32         for(int j=n;j;j--){
    33             while(R&&b[i][j]>st[R])R--;
    34             r[i][j]=R?num[R]-1:n;
    35             st[++R]=b[i][j];
    36             num[R]=j;
    37         }
    38         for(int j=1;j<=n;j++){
    39             sq[l[i][j]][j]+=b[i][j];
    40             sq[l[i][j]][r[i][j]+1]-=b[i][j];
    41             sq[j+1][j]-=b[i][j];
    42             sq[j+1][r[i][j]+1]+=b[i][j];
    43         }
    44     }
    45     for(int i=1;i<=n;i++){
    46         for(int j=1;j<=n;j++){
    47             sq[i][j]+=sq[i][j-1];
    48         }
    49         for(int j=1;j<=n;j++){
    50             sq[i][j]+=sq[i-1][j];
    51         }
    52         for(int j=i;j<=n;j++){
    53             ans=max(ans,sq[i][j]-pre[j]+pre[i]);
    54         }
    55     }
    56     printf("%lld",ans);
    57     return 0;
    58 } 
  • 相关阅读:
    C++ 友元(friend关键字)、类中的重载、操作符重载(operator关键字)
    C++ 二阶构造模式
    C++ 对象构造顺序、构析函数、临时对象。
    C++ 初始化列表
    C++ 对象的构造
    C++ 类学习笔记 :: 作用域限定符
    linux和window下生成任意大小的文件
    RobotFramework和Eclipse集成-安装和使用说明
    Linux中判断一个命令是否执行成功
    xpath 轴定位表达方式
  • 原文地址:https://www.cnblogs.com/dcdcbigbig/p/9630101.html
Copyright © 2011-2022 走看看