题意:给定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;
}