51nod 1624

题意:给定3*n的矩阵,求模P下的路径权值总和最大值。
每次移动都只能向右或者向下走,那么一条完整的路径必然是由
(1,1)->(1,L)->(2,L)->(2,R)->(3,R)->(3,n)。
先预处理出road[i],road[i]代表从(2,1)->(2,i)->(3,i)->(3,n)的路径权值总和和,并插入multiset。
再枚举L:1~n,每次对于L,计算sum[L]:(1,1)->(1,L)权值总和,那么total_weight=sum[L]-sum2[L-1]+road[i] (sum2[L]是(2,1)->(2,L)的权值和)。显然对于模P意义下的两数相加,只有两种情况:
1)a+b∈[0,p)
2)a+b∈[p,2p)
那么我们在multiset中查询两种情况:
1)max(road[i])
2)不超过p-1-pre的最大值(pre=sum[L]-sum2[L-1])
当然,当枚举到L时,必须删去road[1]…road[L-1],否则会产生(1,1)->(1,L)->(2,L-x)->(2,L-x+y)->(3,L-x+y)->(3,n)的路径,显然这是不合法的。(x,y>=0)

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <limits.h>
#include <queue>
#include <set>
#include <map>
#include <vector>
#include <algorithm>
#define LL long long
#define cl(a, b) memset(a, b, sizeof a)
using namespace std;
const int mod=100000000;
const int maxn=1e5+10;
const int Inf = 0x3f3f3f3f;
int n, p;
int a[4][maxn];
int sum[4][maxn];
int road[maxn];
multiset<int> S;
multiset<int>::iterator it;
int main(){

    scanf("%d%d",&n, &p);
    for(int i=1;i<=3;i++)
        for(int j=1;j<=n;j++)
        scanf("%d",&a[i][j]);
    for(int i=1;i<=3;i++)
        for(int j=1;j<=n;j++){
            sum[i][j]=(sum[i][j-1]+a[i][j])%p;
    }
    for(int i=1;i<=n;i++){
        road[i]=(sum[2][i]+(sum[3][n]-sum[3][i-1]+p)%p)%p;
        S.insert(road[i]);
    }
    int ans=0;
    for(int L=1;L<=n;L++){
        int pre=(sum[1][L]-sum[2][L-1]+p)%p;
        if(L>1){
            int x=road[L-1];
            S.erase(S.find(x));
        }
        it=S.end(); it--;
        ans=max(ans, (pre+(*it))%p);
        it=S.lower_bound(p-pre);
        if(it==S.begin()) continue;
        it--;
        ans=max(ans, (pre+(*it))%p);
    }
    printf("%d\n",ans);

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值