1624 取余最长路 (前缀和+set二分)

1624 取余最长路

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

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

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

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

样例解释:

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

Input

单组测试数据
第一行两个数n(1<=n<=100000),p(1<=p<=1000000000)。
接下来3行,每行n个数,第i行第j列表示a[i][j]表示该点的权(0<=a[i][j]<p)。

Output

一个整数表示答案。

Input示例

2 3
2 2
2 2
0 1

Output示例

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 这个很重要 数据n<=10^5 所以 n^2 枚举会超时 或许我们可以从两个拐点的关系上下手 因为x<=y 所以我们可以O(n) 枚举x 把sum[1][x]+sum[2][x-1] 放入一个集合 
二分查找 大于等于sum[2][y]+sum[3][n]-sum[3][y-1]的值 这样就把复杂度降到 O(nlongn) 

 1 #include <set>
 2 #include <cstdio>
 3 #include <cctype>
 4
 5 const int MAXN=100010;
 6
 7 typedef long long LL;
 8
 9 int n,p;
10
11 LL ans;
12
13 LL sum[4][MAXN];
14
15 inline void read(LL&x) {
16     int f=1;register char c=getchar();
17     for(x=0;!isdigit(c);c==‘-‘&&(f=-1),c=getchar());
18     for(;isdigit(c);x=x*10+c-48,c=getchar());
19     x=x*f;
20 }
21
22 int hh() {
23     scanf("%d%d",&n,&p);
24     for(int i=1;i<=3;++i)
25       for(int j=1;j<=n;++j)
26         read(sum[i][j]),sum[i][j]=(sum[i][j]+sum[i][j-1])%p;
27     std::set<LL> s;
28     std::set<LL>::iterator it;
29     for(int i=1;i<=n;++i) { // 在一个循环中 保证了x<=y
30                                             // 不在一个循环中 可能会出现 向左走的情况  即 x>y 这是不合法的
31          LL t=(sum[1][i]-sum[2][i-1]+p)%p;
32         s.insert(t);
33         t=(sum[2][i]-sum[3][i-1]+sum[3][n]+p)%p;
34         it=s.lower_bound(p-t);
35         if(it!=s.begin()) ans=ans>(t+*(--it))%p?ans:(t+*it)%p;
36     }
37     printf("%lld\n",ans);
38     return 0;
39 }
40
41 int sb=hh();
42 int main(int argc,char**argv) {;}

代码


 
时间: 2024-10-13 10:59:03

1624 取余最长路 (前缀和+set二分)的相关文章

1624 取余最长路(set)

1624 取余最长路 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 佳佳有一个n*m的带权矩阵,她想从(1,1)出发走到(n,m)且只能往右往下移动,她能得到的娱乐值为所经过的位置的权的总和. 有一天,她被下了恶毒的诅咒,这个诅咒的作用是将她的娱乐值变为对p取模后的值,这让佳佳十分的不开心,因为她无法找到一条能使她得到最大娱乐值的路径了! 她发现这个问题实在是太困难了,既然这样,那就只在3*n的矩阵内进行游戏吧! 现在的问题是,在一个3*n的带权矩阵中,从(

51 nod 1624 取余最长路 思路:前缀和 + STL(set)二分查找

题目: 写这题花了我一上午时间. 下面是本人(zhangjiuding)的思考过程: 首先想到的是三行,每一行一定要走到. 大概是这样一张图 每一行长度最少为1.即第一行(i -1) >= 1,第二行 (j - i) >= 1,第三行 (n - j) >= 1. 我们要求的就是这条路径上的和. 我们发现只要 i 和 j 固定了,结果就固定了. 如果每次都要重新求和的话时间复杂度肯定不够,所以我这个时候想到了前缀和. 用sum[a][b]表示第a行(总共只有3行)前b个数字的和. 第一行可

51nod1624 取余最长路 前缀和 + set

由于只有3行,因此只会会换行2次,假设$x, y$分别为这两次的换行点 那么答案为$S[1][x] +S[2][y] - S[2][x - 1] + S[3][n] - S[3][y - 1]$ 其中,$S[i]$表示第$i$行的前缀和 令$a[x] = S[1][x] - S[2][x - 1], b[y] = S[2][y] - S[3][y - 1]$ 考虑枚举$x$,那么问题转化为询问在一堆数中求一个数$k$使得$v (= a[x] + S[3][n]) + k \;mod\;p$最大

51nod 1624 取余最短路(set)

题意: 佳佳有一个n*m的带权矩阵,她想从(1,1)出发走到(n,m)且只能往右往下移动,她能得到的娱乐值为所经过的位置的权的总和. 有一天,她被下了恶毒的诅咒,这个诅咒的作用是将她的娱乐值变为对p取模后的值,这让佳佳十分的不开心,因为她无法找到一条能使她得到最大娱乐值的路径了! 她发现这个问题实在是太困难了,既然这样,那就只在3*n的矩阵内进行游戏吧! 现在的问题是,在一个3*n的带权矩阵中,从(1,1)走到(3,n),只能往右往下移动,问在模p意义下的移动过程中的权总和最大是多少. 实际上路

简单Dp----最长公共子序列,DAG最长路,简单区间DP等

/* uva 111 * 题意: * 顺序有变化的最长公共子序列: * 模板: */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int a[100]; int mu[100]; int Dp[100][100]; int main() { int n,x; scanf("%d", &n

【分治】取余运算

问题 E: [分治]取余运算 时间限制: 1 Sec  内存限制: 128 MB提交: 16  解决: 6[提交][状态][讨论版] 题目描述 输入b,p,k的值,求bp mod k的值.其中b,p,k*k为长整型数. 输入 三个整数,分别为b,p,k的值 输出 bp mod k 样例输入 2 10 9 样例输出 2^10 mod 9=7 提示 解题思路:分治,顾名思义,把一个大问题分解为多个小问题. 这里有一个公式,利用这个公式通过递归求得. 代码: #include <iostream>

kb-01-e&lt;取余操作,宽搜,巧妙&gt;;

题目描述: n属于1到200,找到对应的一个数只含有0和1,并且是n的倍数: 分析: 本题有几个数会是大数:所以要考虑大数: 用到余数的性质:例如n=6,1%6=1: 1*10%6=4:              (1*10+1)%6=5: 4*10%6=4:               (4*10+1)%6=5: 5*10%6=2:                (5*10+1)%6=3: (重复4,5) 2*10%6=2:                  ....=3: 3*10%6=0:

poj 3349:Snowflake Snow Snowflakes(哈希查找,求和取余法+拉链法)

Snowflake Snow Snowflakes Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 30529   Accepted: 8033 Description You may have heard that no two snowflakes are alike. Your task is to write a program to determine whether this is really true. Y

Luogu P1226 取余运算||快速幂(数论,分治)

P1226 取余运算||快速幂 题目描述 输入b,p,k的值,求b^p mod k的值.其中b,p,k*k为长整型数. 输入输出格式 输入格式: 三个整数b,p,k. 输出格式: 输出"b^p mod k=s" s为运算结果 输入输出样例 输入样例#1: 2 10 9 输出样例#1: 2^10 mod 9=7 这是一道很有趣的水题,如果知道公式. 一般求解会溢出,导致答案错误. 这里介绍取模的一个公式: a*b%k=(a%k)*(b%k)%k. 在我们这道题中是b^p = (b^(p/