51nod 1624 取余最短路(set)

题意:

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

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

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

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

实际上路径总是第一行1-i,第二行i-j,第三行j-n.

考虑问题的补,先求出矩阵的总和%p,不妨设为sum,那么减去没有走过的格子总和%p,不妨设为val。

而这个val可以表示为两个数列的前缀和和后缀和的值之和,需要动态调整找到最大的方案,使用set可以达到这个目标。

时间复杂度O(nlogn).

# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <bitset>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-8
# define MOD 1000000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FDR(i,a,n) for(int i=a; i>=n; --i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
inline int Scan() {
    int x=0,f=1; char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘) f=-1; ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘; ch=getchar();}
    return x*f;
}
inline void Out(int a) {
    if(a<0) {putchar(‘-‘); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+‘0‘);
}
const int N=100005;
//Code begin...

int a[4][N], inv1[N], inv2[N], sum1[N], sum2[N], n, p;
set<int>vv;
set<int>::iterator it;

void init(){
    FOR(i,1,n) inv1[i]=(inv1[i-1]+a[2][i])%p, sum2[i]=(sum2[i-1]+a[3][i])%p;
    FDR(i,n,1) inv2[i]=(inv2[i+1]+a[2][i])%p, sum1[i]=(sum1[i+1]+a[1][i])%p;
    FOR(i,0,n-1) inv1[i]=(inv1[i]+sum1[i+2])%p;
    FDR(i,n+1,2) inv2[i]=(inv2[i]+sum2[i-2])%p;
}
int main ()
{
    int sum=0, ans=0;
    n=Scan(); p=Scan();
    FOR(i,1,3) FOR(j,1,n) a[i][j]=Scan(), sum=(sum+a[i][j])%p;
    init();
    FDR(i,n-1,0) {
        vv.insert(inv2[i+2]);
        int val=(sum-inv1[i]+p+1)%p;
        it=vv.lower_bound(val);
        if (it==vv.end()) it=vv.begin();
        ans=max(ans,((sum-inv1[i]-*it)%p+p)%p);
    }
    printf("%d\n",ans);
    return 0;
}

时间: 2025-01-05 18:22:34

51nod 1624 取余最短路(set)的相关文章

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

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

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个数字的和. 第一行可

POJ 3070 + 51Nod 1242 大斐波那契数取余

POJ 3070 #include "iostream" #include "cstdio" using namespace std; class matrix { public: int a[2][2]; matrix() { a[0][0]=a[1][0]=a[0][1]=1; a[1][1]=0; } }; matrix multi(matrix a,matrix b) { matrix temp; int i,j,k; for(i=0;i<2;i++)

【66测试20161115】【树】【DP_LIS】【SPFA】【同余最短路】【递推】【矩阵快速幂】

还有3天,今天考试又崩了.状态还没有调整过来... 第一题:小L的二叉树 勤奋又善于思考的小L接触了信息学竞赛,开始的学习十分顺利.但是,小L对数据结构的掌握实在十分渣渣.所以,小L当时卡在了二叉树. 在计算机科学中,二叉树是每个结点最多有两个子结点的有序树.通常子结点被称作“左孩子”和“右孩子”.二叉树被用作二叉搜索树和二叉堆.随后他又和他人讨论起了二叉搜索树.什么是二叉搜索树呢?二叉搜索树首先是一棵二叉树.设key[p]表示结点p上的数值.对于其中的每个结点p,若其存在左孩子lch,则key

java中的基本运算符、取余、逻辑运算符、逻辑运算符、位运算符、移位运算符

注意事项: 常量在编译的时候会赋值,变量在运行的时候才在内存中分配空间赋值. 赋值运算符 += -+ *+ %= \= 在java编译器会进行强制类型转换 取余: 在java中做取余运算的是时候,结果的正负号是取决于被除数. 逻辑运算符&且 |或 !非 ^异或 &&短路与 ||短路或 位运算符:直接操作二进制位的. & (与) 6 & 3 = 2 0000 0110 可以把1看成true & 0000 0011 0看成false --------------

同余最短路

同余最短路其实是一种优化最短路建图的方法. 通常是解决给定m个整数,求这m个整数能拼凑出多少的其他整数(这m个整数可以重复取)或给定m个整数,求这m个整数不能拼凑出的最小(最大)的整数. 我们通过一道例题来讲解. P3403 跳楼机 简化一下题意:用a,b,c(这里用a,b,c来代替x,y,z)三个数能组成几个小于h的整数.$h \leq 2^{63}-1$ 因为h过大所以直接建图显然是不行的,我们要优化空间. 我们因为这个跳的顺序是无关的,所以每个数都可以由若干次b/c再加上若干次a而形成的.

加/减/乘/除 下的取余

x(负数) mod y(正数) = z 其中x<z<=0 , 且(z-x) mod y=0. 求法:z=x+abs(x)/y*y (这里的除法结果向下取整) 所以当求一个数经过各种计算后的取余,只需 ans=(ans+x*y)%yu ans=(ans-x*y)%yu ans=ans*x%yu 除法:用线性逆元 最后 ans=(ans+yu)%yu (要是之前有减法运算)

salesforce 零基础学习(四十三)运算取余

工作中遇到一个简单的小问题,判断两个数是否整除,如果不整除,获取相关的余数. 习惯java的我毫不犹豫的写下了代码 public Boolean isDivisibility(Integer dividend,Integer divider) { return dividend % divider == 0; } 提交代码发现竟然提交不上?? 后来查看API发现apex中没有直接的%取余运算,所以如果想要取余以及判断是否整除需要其他方式,代码如下: public without sharing