51nod 1624 取余最长路 (set 二分)

简介: 51nod 1624 取余最长路 (set 二分)

佳佳有一个n*m的带权矩阵,她想从(1,1)出发走到(n,m)且只能往右往下移动,她能得到的娱乐值为所经过的位置的权的总和。


有一天,她被下了恶毒的诅咒,这个诅咒的作用是将她的娱乐值变为对p取模后的值,这让佳佳十分的不开心,因为她无法找到一条能使她得到最大娱乐值的路径了!


她发现这个问题实在是太困难了,既然这样,那就只在3*n的矩阵内进行游戏吧!


现在的问题是,在一个3*n的带权矩阵中,从(1,1)走到(3,n),只能往右往下移动,问在模p意义下的移动过程中的权总和最大是多少。


样例解释:

移动的方案为“下下右”。


输入

单组测试数据

第一行两个数n(1<=n<=100000),p(1<=p<=1000000000)。

接下来3行,每行n个数,第i行第j列表示a[i][j]表示该点的权(0<=a[i][j]<p)。

输出

一个整数表示答案。

输入样例

2 3

2 2

2 2

0 1

输出样例

2


很容易看出来 整条路径分成三行 只有两个拐点


路径中是有三条线段的 我们可以统计每一行的前缀和


所以我们有下面的计算公式 sum[1][x]+sum[2][y]-sum[2][x-1]+sum[3][n]-sum[3][y-1]

把上述式子换一下位置 sum[1][x]-sum[2][x-1] + sum[2][y]+sum[3][n]-sum[3][y-1]

所以 我们可以想到来枚举 x 和 y 寻找最长路径 从图中可以看出 两个拐点的关系 x<=y 这个很重要

考虑枚举x,那么问题转化为询问在一堆数中求一个数k使得v(=a[x]+S[3][n])+k mod p最大


分两种情况考虑,第一种v+k∈[v,mod−1],那么k∈[0,mod−k−1],并且k越大越好


第二种不如第一种好,但有可能不得不选,v+k∈[1,v−1],同样时k越大越好


也就是说,需要一种支持插入,查询前驱和最大值的数据结构,set就可以

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
int a[maxn], b[maxn];
int sum[4][maxn];
int n, mod, x;
set<int> st;
set<int> ::iterator it;
int main() {
  scanf("%d%d", &n, &mod);
  for (int i = 1; i <= 3; i++) {
    for (int j = 1; j <= n; j++) {
      scanf("%d", &x); 
      sum[i][j] = (sum[i][j - 1] + x) % mod;
    }
  }
  for (int i = 1; i <= n; i++) {
    a[i] = ((sum[1][i] - sum[2][i - 1]) % mod + mod) % mod;
    b[i] = ((sum[2][i] - sum[3][i - 1]) % mod + mod) % mod;
  }
  int res = sum[3][n];
  int ans = 0;
  st.insert(-1);
  for (int i = n; i >= 1; i--) {
    st.insert(b[i]);
    int tmp = (res + a[i]) % mod;
    x = ((mod - tmp - 1) % mod + mod) % mod;
    it = st.lower_bound(x);
    ans = max(ans, (tmp + *(--st.end())) % mod);
    ans = max(ans, (tmp + *it) % mod);
    it--;
    if (*it != -1) {
      ans = max(ans, (tmp + *it) % mod);
    }
  }
  printf("%d\n", ans);
  return 0;
}
相关文章
|
6月前
|
算法 测试技术 C#
【二分查找】【map]436. 寻找右区间
【二分查找】【map]436. 寻找右区间
|
6月前
|
机器学习/深度学习
【每日一题Day271】LC918环形子数组的最大和 | 分类讨论 + dp
【每日一题Day271】LC918环形子数组的最大和 | 分类讨论 + dp
52 0
【每日一题Day271】LC918环形子数组的最大和 | 分类讨论 + dp
|
6月前
【每日一题Day306】LC228汇总区间 | 双指针
【每日一题Day306】LC228汇总区间 | 双指针
38 0
51nod 1711 平均数(二分 + 树状数组好题)
51nod 1711 平均数(二分 + 树状数组好题)
95 0
51nod 1255 字典序最小的子序列 (贪心 + stack)
51nod 1255 字典序最小的子序列 (贪心 + stack)
94 0
|
C++
C/C++每日一练(20230515) 区间和的个数、BST最近公共祖先、最接近元素
C/C++每日一练(20230515) 区间和的个数、BST最近公共祖先、最接近元素
94 0
51nod 1292 字符串中的最大值 V2 (后缀数组)
51nod 1292 字符串中的最大值 V2 (后缀数组)
57 0
求旋转数组(左旋和右旋)的常用两个方法(详解)
求旋转数组(左旋和右旋)的常用两个方法(详解)
185 0
求旋转数组(左旋和右旋)的常用两个方法(详解)
UPC Graph (最小生成树 || 并查集+二分)
UPC Graph (最小生成树 || 并查集+二分)
93 0